垃圾收集器需要做的三件事情
- 哪些内存需要回收?
- 什么时候回收?
- 如何回收?
哪些内存什么时候需要回收
对象是否已经宣告死亡?在Java堆中存放着几乎所有的对象实例,垃圾收集器在回收前的第一件事就是确定堆中哪些对象还“存活”着,哪些已经“死去”。
垃圾判定算法
引用计数算法
通过给每个对象添加一个引用计数器,每引用一次,计数器加一;当引用失效,计数器减一。当对象的计数器为0时说明对象不再被使用。引用计数器会增加对象占用的内存,还需要大量额外工作才能保证正确的工作,并且难以解决对象之间相互循环引用的问题。所以JVM没有选择引用计数器算法来管理内存,而是通过可达性分析确定对象是否存活的。
可达性分析算法
算法从GC Roots开始,向下搜索引用链上的可达对象。搜索结束后那些无法从GC Roots可达的对象会至少经历一次标记过程,第一次标记会判定是否需要执行finalize方法(有覆盖或者未被虚拟机调用finalize方法才需要执行),如果需要执行finalize,对象会被放入F-Queue中等待低优先级的Finalizer线程调用执行;稍后收集器会堆F-Queue中的对象进行第二次标记。在标记之后如果对象还没有在可达调用链上,将被认定为对象已经死亡,内存可以回收。为了保证可达性分析的正确性,需要将堆中对象的引用范围扩大到其它内存区域,因为堆中的对象完全有可能被位于其它区域的内存所引用。
GC Roots 一系列引用链上的初始节点的集合,通过这些节点集合可以搜索到所有的引用链。可以作为GC Roots对象包括:参数、局部变量、临时变量;静态属性引用的对象、常量引用的对象;JNI引用的对象;基本类型对应的Class对象、常驻的异常对象(NullPointException、OutOfMemoryError等)、系统类加载器;被同步锁持有的对象。
内存如何回收
垃圾收集算法
只分析和“可达性分析”算法相关的垃圾收集算法。
分代收集理论
三条经验法则
- 弱分代假说:绝大部分对象都是朝生夕灭的。
- 强分代假说:熬过越多次垃圾收集过程的对象就越难以消亡。
- 跨代引用假说:跨代引用相对同代引用来说仅占极少数。
对一个对象的一次尝试回收内存,标志着对象的年龄就增加了,随着对象经历的垃圾收集次数越多,对象就越难以消亡。因为随着年龄的增加,对象进入老年代,而垃圾收集器对老年代的内存收集频率较低,从而进入老年代的对消会存活的越久。
垃圾收集器将大部分的时间用来关注新生代的对象收集,能以较低代价回收到大量的空间;而那些难以消亡的老年代集中放在一块,JVM可以使用较低的频率来回收这个区域。这就同时兼顾了垃圾收集的时间开销和内存空间的有效利用。
收集行为
- 新生代收集(Minor GC/Young GC):值目标只是新生代的垃圾收集。
- 老年代收集(Major GC/Old GC):指目标只是老年代的垃圾收集。
- 混合收集(Mixed GC):收集整个新生代和部分老年代。
- 整堆收集(Full GC):收集整个Java堆和方法区。
标记-清除算法
算法分为“标记”和“清除”两个阶段:首先标记所有需要回收的对象,之后统一回收掉所有被标记的对象;也可以反过来,标记存活的对象,统一回收未被标记的对象。标记-清除算法是最基础的算法,基本都是对这个算法的优化改进。
缺陷一:执行效率不稳定,当Java堆中存在大量需要被回收的对象,就必须进行大量的标记和清除动作。
缺陷二:内存空间碎片化,标记、清除后会产生大量不连续的内存碎片。
标记-复制算法
该改进算法一定程度上解决了“标记-清除”算法的两个缺陷。算法将内存按容量划分为大小相等的两块,每次只使用其中的一块,当这一块的内存用完了,就将还存活的对象复制到另一块上面,然后把使用过的一块空间一次清理掉。对于多数对象都是可回收的情况,算法需要复制的对象就较少,也不用做多余的标记工作,从而执行效率一定程度上有提升。因为每次回收垃圾时,存活对象复制到另一个内存块中,使得对象在内存上可以实现连续,不会出现内存碎片。
引出一个缺陷:将可用内存缩小为原来的一半。根据经验法则一:“大多数对象熬不过第一次垃圾收集”,可以将内存划分进一步优化,从而解决问题,但依然存在或多或少的问题需要考虑。
标记-整理算法
标记-复制算法在存活对象较多的情况下需要执行较多的复制操作,效率将从而降低。所以“标记-复制”算法被应用在新生代对象的垃圾收集上,“标记-整理”算法针对的是老年代对象的收集。
标记过程与“标记-清除”算法一致,但后续不是对可回收对象进行清理,而是让所有存活的对象都向内存空间的一端移动,然后清理掉边界以外的内存。
由于对象的移动需要较长时间的停顿用户进程,造成一定的延迟,但不移动又会产生内存碎片增加内存分配的负担,所以不同的JVM针对不同的场景使用不同的算法。关注吞吐量则使用“标记-整理”算法;关注延迟则使用“标记-清理”算法。