
GC:垃圾回收机制
GC作用区:Heap 和 方法区;
JVM在进行GC时,大部分时候,回收的都是新生代。
类型
- 轻GC(GC),大部分时候清理新生代,偶尔幸存区
- 重GC(全局GC),
如何判断哪些对象需要被回收
Java 垃圾回收判断哪些对象需要被回收有两种方法:引用计数法和可达性分析算法。
可达性分析算法
通过一系列称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的。
GC Roots
GC Roots,tracking GC的根集合,是一组必须活跃的引用。
可以作为GC Roots的对象包括下面几种:
- 在虚拟机栈中引用的对象,譬如各个线程被调用的方法堆栈中使用到的参数、局部变量、临时变量等;
- 在方法区中类静态属性引用的对象,譬如Java类的引用类型静态变量;
- 在方法区中常量引用的对象,譬如字符串常量池里的引用;
- 本地方法栈中JNI(Native方法)引用的对象;
- Java虚拟机内部的引用,如基本数据类型对应的CLass对象,一些常驻的异常对象(比如NullPointException,OutOfMemoryError)等,还有系统类加载器;
- 所有被同步锁(synchronized关键字)持有的对象;
- 反映Java虚拟机内部情况的JMXBean、JVMTI中注册的回调、本地代码缓存等;
- 根据用户所选用的垃圾收集器以及当前回收的内存区域不同,“临时性”地加入的其他对象。
Tracing GC
根本思路
给定一个集合的引用作为根出发,通过引用关系遍历对象图,能被遍历到的(可达到的)对象就判定为存活,其余对象(没有被遍历到的)就自然判定为死亡。
注意:tracing GC的本质是通过找出所有活对象来吧其余空间认定为“无用”,而不是找出所有死掉的对象并回收他们占用的空间。
GC Roots引用例子
在上图中,reference1、reference2、reference3都是GC Roots;
其中:
- reference1 -> 对象实例1
- reference2 -> 对象实例2
- reference3 -> 对象实例4 -> 对象实例6
可以得出对象实例1、2、4、6都具有GC Roots可达性、也就是存活对象,不会被GC回收的对象;
而对于3、5是GC Roots不可达对象,是需要被GC回收的对象。
不可达的对象处理
不可达的对象将暂时处于“缓刑”阶段,要真正宣告一个对象死亡,至少要经历两次标记过程:
当对象变成GC Roots不可达时,GC会判断该对象是否有重写finalize方法,若没有,则直接回收,若有,进入第二步
若对象执行过finalize方法,则进行回收;若对象未执行过finalize方法,将其放入F-Queue队列,虚拟机会稍后建立一个低优先级线程Finalizer去执行该队列中对象的finalize方法,执行finalize方法结束后,GC会再次判断该对象是否科大,若不可达,则进行回收,若可达,则对象列为存活对象。

这里的执行表示虚拟机会执行该方法,但不承诺等待它运行结束。
算法
分类
标记清除法,标记整理,复制算法,引用计数器。
引用计数法
复制算法
复制 + 清除垃圾
复制算法主要体现在新生区的幸存区。
过程
为表明算法过程,先将幸存区分成两个区:A区和B区
- 新生对象会被分配到A区的未使用内存中,当A区内存满了,就把A区存活对象复制到B区;
- 然后清理A区所有对象;
- 新生对象会被分配到B区未使用的内存中,当B区满了,就把B区存活对象复制到A区;
- 清理B区所有对象;
- 按照上面的过程循环
在Java里,一般将空的内存称为to区,当前正在使用的内存称为from区。(第二步结束时候,A为to区,B为from区;在第4步结束时候,B成为to区,A为from区)
特点
- 好处:没有内存碎片
- 坏处:浪费了内存空间(to永远为空)
复制算法最佳使用场景:对象存活度较低的时候。
标记清除算法
每经历一次GC,会进行可达性分析,标记GC Roots可达的对象,清理没有被标记的对象。
特点
优点:不需要额外的空间。
缺点:两次扫描,严重浪费时间,会产生内存碎片。
标记压缩算法
标记清除算法的优化版本,每经历几次GC,会进行一次扫描,然后将对象移动到内存的一端,防止内存碎片产生。
GC总结
内存效率最高(时间复杂度):复制算法 > 标记清除算法 > 标记压缩算法
内存整齐度:复制算法 > 标记压缩算法 = 标记清除算法
内存利用率:标记压缩算法 = 标记清除算法 > 复制算法
没有最好的算法,只有最合适的算法。
GC:分代收集算法
结论
年轻代:存活率低 —>复制算法
老年代:区域大,存活率高 —> 标记清除(内存碎片不是太多) + 标记压缩 混合实现
书籍
《深入理解JVM》
其他
从文章中删除的内容
对象的标记
对象由两种状态,涉及到两类状态空间:
- 一个是终结动态空间F = {unfinalized,finalizable,finalized}
- 一个是可达状态空间R = {reachable,finalizer-reachable,unreachable}。
各状态含义如下:
unfinalized:GC未准备执行其finalize方法,新建对象会先进入此状态;
finalizable:表示可以执行finalizable方法,GC已检测到对象不可达;
finalized:表示GC已对对象执行过finalize方法;
reachable:表示GC Roots引用可达;
finalizer-reachable(f-reachable):表示不是reachable,但通过某个finalizable对象可达;
unreachable:对象不可通过上面两种途经可达;
执行过程:
- 新建对象首先处于{reachable,unfinalized}状态;
- 若引用关系消失,从reachable变为f-reachable或unreachable状态;
- 若JVM….Delete