判断对象的状态
在垃圾回收器对对象进行回收之前首先需要判断对象是否存活,即是否会被引用。若对象不再被任何途经使用,则回收它,否则需要保留该对象。判断对象是否存活主要由以下两种算法。
引用计数法
给对象添加一个引用计数器,对象被引用计数器加一,引用失效减一,若计数器为零则说明对象没有被引用。
该算法实现简单,但主流虚拟机都没有采用该算法,因为该算法无法解决循环引用的问题。即有A,B两个对象,A中某个字段指向B,B中某个字段指向A,两者计数器都不为零,但实际上两者都不会被使用,然而垃圾回收器却无法回收。
可达性分析算法
该算法是目前的主流实现算法,该算法的核心思想是通过一系列的对象作为起始点(称为“GC Roots”),由该节点中所引用的对象开始向下搜索,搜索所走过的路径称为“引用链”,若某对象无法与任何引用链相连,说明该对象不可用,虚拟机将判定其为可回收。
如图所示,obj6,obj7,obj8虽然相互有引用,但他们与GC Roots没有联系,因此他们将会被判定为可回收。
在java中,可作为GC Roots的对象有以下几种:
- 虚拟机栈(栈帧中的本地变量表)所引用的对象
- 方法区中静态类型引用的变量
- 方法区中常量引用的对象
- 本地方法栈(native方法)引用的对象
垃圾收集算法
标记-清除算法
该算法是最基础的垃圾回收算法,后续算法都是在该基础之上进行改进而来。该算法分为两个阶段:
- 标记:标记出所有需要回收的对象
- 回收:将标记好的对象统一进行回收
该算法存在的问题:一是效率问题,标记和清除效率都不高。二是空间问题,会产生大量不连续的内存碎片,碎片过多会导致分配较大对象时无法找到足够的可用内存,进而提前触发垃圾回收动作。
复制算法
复制算法解决了标记清除算法的效率问题,复制算法将内存划分为大小相等的两块,每次只使用其中的一块。当这块内存用完后将所有存活的对象复制到另一块内存中,并清空当前这块内存。复制算法每次只对两块内存中的一块进行回收,也无需考虑内存碎片的问题。但该算法将内存缩小为原来的一半,比较浪费内存。
当前主流虚拟机都以该算法来回收新生代。
标记-整理算法
标记的过程和标记-清除算法一致,但标记完不是直接清除,而是将存活的对象移到一边,直接将另外的内存清除。
分代收集算法
当前商业虚拟机的算法都采用的事分代收集算法,即根据对象生命周期的不同将内存分为几块。java堆内存分为新生代和老年代。新生代存活率低,大量对象死去,因此选用复制算法。老年代存活率高,复制算法需要较多内存,因此选用标记-清除算法或标记-整理算法。
内存分配策略
对象优先分配在eden区
大多数情况下,对象在新生代的eden区中分配。若eden区没有足够的空间,虚拟机将发起一次Minor GC。
大对象直接进入老年代
大对象是指需要大量连续内存空间的对象。经常出现大对象会导致内存中还有空间但提前触发垃圾收集以获取足够的连续空间来安置它。
可以设置虚拟机的-XX:PretenureSizeThreshold值,当对象大小超过设置的值时直接进入老年代,避免在eden区和两个survivor区发生大量内存复制。
长期存活的对象进入老年代
虚拟机为每一个对象设置了一个年龄计数器,当对象在eden区经历第一次Minor GC后仍然存活,则对象会被移到survivor区,并将年龄设为1。在survivor区每经历一次Minor GC年龄加1,当年龄达到一定阈值(默认15)将会被晋升到老年区。阈值可通过 -XX:MaxTenuringThreshold 进行设置。
动态判定对象年龄
survivor中对象并非年龄一定要达到MaxTenuringThreshold才会进入老年代。若survivor中相同年龄的对象的大小总和超过survivor空间的一半,则虚拟机会将年龄大于等于该年龄的对象直接移到老年区。
空间分配担保
在发生Minor GC时,虚拟机会检查老年代连续的空闲区域是否大于新生代所有对象的总和,若成立,则说明Minor GC是安全的,否则,虚拟机需要查看HandlePromotionFailure的值,看是否运行担保失败,若允许,则虚拟机继续检查老年代最大可用的连续空间是否大于历次晋升到老年代对象的平均大小,若大于,将尝试进行一次Minor GC;若小于或者HandlePromotionFailure设置不运行冒险,那么此时将改成一次Full GC,以上是JDK Update 24之前的策略,之后的策略改变了,只要老年代的连续空间大于新生代对象总大小或者历次晋升的平均大小就会进行Minor GC,否则将进行Full GC。
冒险是指经过一次Minor GC后有大量对象存活,而新生代的survivor区很小,放不下这些大量存活的对象,所以需要老年代进行分配担保,把survivor区无法容纳的对象直接进入老年代。
垃圾收集器
参考这篇文章《Java虚拟机垃圾回收(三) 7种垃圾收集器 主要特点 应用场景 设置参数 基本运行原理》
参考
- http://www.cnblogs.com/parryyang/
- https://www.cnblogs.com/xiaoxi/p/6557473.html
- 《深入理解Java虚拟机:JVM高级特性与最佳实践(第2版)》