本文将主要介绍jvm的垃圾回收机制。在讲解之前,先放出几道GC面试题。
- JVM的内存模型和分区,详细到每个区放什么
- 堆里面的分区有哪些?Eden,from,to,老年区,说说他们的特点
- 轻GC和重GC分别在什么时候发生?
- GC算法有哪些?复制算法,标记清除法,标记压缩,怎么用的?
相信在看完Java学习笔记——JVM快速入门(一)和Java学习笔记——JVM快速入门(二)之后,对前三道题已经能够回答出来了,本文将围绕第四道题进行讲解。
一、GC是什么?作用区域在哪?
GC(Garbage Collection)是垃圾回收机制。
JVM GC只回收堆区和方法区内的对象。
二、GC对象存活判断
判断对象是否存活一般有两种方式:
- 引用计数:每个对象有一个引用计数属性,新增一个引用时计数加1,引用释放时计数减1,计数为0时可以回收。此方法简单,无法解决对象循环引用的问题。
- 可达性分析(Reachability Analysis):从GC Roots开始向下搜索,搜索所走过的路径称为引用链。当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的。不可达对象。
补充
1.在Java语言中,GC Roots包括以下几类元素
- 虚拟机栈(栈帧中的本地变量表)中引用的对象
- 本地方法栈中JNI(即一般说的Native方法)引用的对象
- 方法区中类静态属性引用的对象
- 方法区中常量引用的对象
不清楚的可看参考资料5。
三、GC垃圾回收算法
1.复制算法
新生区主要用的复制算法。
在解释原理之前,先理解一下幸存区谁是to的问题,谁空谁是to(即to区必为空)。
原理
Survivor区中,一块叫From,一块叫To,对象存在Eden和From块。当进行GC时,Eden存活的对象全移到To块,而From中,存活的对象按年龄值确定去向,当达到一定值(年龄阈值,通过-XX:MaxTenuringThreshold可设置,默认=15)的对象会移到年老代中,没有达到值的复制到To区,然后直接清空Eden和From。之后,From和To交换角色,新的From即为原来的To块,新的To块即为原来的From块,且新的Form块中对象年龄加1。
如果上述文字没有理解,下面我将配合着图进行讲解。
从左边的图可以看出,一开始对象存在于Eden区和From区,将Eden区存活的对象全部移动到To区中,判断From中的对象是否到达了年龄,对到达年龄的一部分移动到养老区(老年区),最后将From区和To区互换,并对From区的年龄加1,如右图所示。
- 优点:没有内存碎片
- 缺点:
- 空间浪费:可用内存缩减为原来的一半,太过浪费(解决:可以改良,不按1:1比例划分);
- 效率随对象存活率升高而变低:当对象存活率较高时,需要进行较多复制操作(对象的引用地址需要复制),效率将会变低,所以该算法不适合对象存活率较高的场景或者区域。
所以复制算法最佳使用场景:对象存活度较低的时候,即新生区
2.标记-清除算法
原理
首先标记出需要回收的对象,标记完成之后统一清除对象。
- 优点:不需要额外的空间
- 缺点:
- 效率问题:两次扫描,严重浪费时间
- 会产生内存碎片
3.标记-压缩算法
原理</