从如何判定消亡的角度出发,垃圾收集算法可以划分为“引用计数式垃圾收集”和“追踪式垃圾收集”两大类。
本文主要介绍的是追踪式垃圾收集。
1. 分代收集理论
当代垃圾收集器大多遵循“分代收集”的理论进行设计,它建立在两个假说之上:
-
弱分代假说:绝大多数对象都是朝生夕灭的。
-
强分代假说:熬过越多次垃圾收集过程的对象就越难以消亡。
以上两个假说共同奠定多款垃圾收集器的设计原则:收集器应将Java堆划分出不同的区域,然后将回收对象依据其年龄分配到不同的区域中存储。
回收类型划分:将Java堆划分出不同区域之后,垃圾收集器每次只回收其中某一个或某部分区域——因而才有“Minor GC”、“Major GC”、“Full GC”这样的回收类型划分。同时也发展出“标记-复制算法”,“标记-清除算法”、“标记-整理算法”等针对性的收集算法。
第三个假说的添加:
-
跨代引用假说:跨代引用相对于同代引用来说仅占极少数。存在互相引用关系的两个对象,是应该倾向于同时生存或同时消亡。
垃圾收集器名词:
-
部分收集(Partial GC):指目标不是完整手机整个Java堆的垃圾收集,其中又分为
-
新生代收集(Minor GC):指目标只是新生代的垃圾收集。
-
老年代收集(Major GC):指目标只是老年代的垃圾收集。。目前只有CMS收集器会有单独收集老年代的行为。
-
混合收集(Mixed GC):指目标是收集整个新生代以及部分老年代的垃圾收集。目前只有G1收集器会有这种行为。
-
-
整堆收集:收集整个Java堆和方法去的垃圾收集。
2. 标记-清除算法
标签:最早出现也是最基础的垃圾收集算法。
过程:首先标记出所有需要回收的对象,在标记完成后,统一回收掉所有被标记的对象。也可以反过来。
优点:
缺点:
-
执行效率不稳定。
-
产生空间碎片化问题,对清除后的对象分配内存不利。
3. 标记-复制算法
标签:为了解决标记-清除算法面对大量可回收对象时执行效率低的问题。
过程:将内存划分为两块相等的大小,每次只使用其中的一块。进行垃圾收集时,将存活的对象复制到另外一块,再把使用的内存块清理掉。
优点:实现简单,运行高效
缺点:代价是将可用内存空间缩小一半。
附录
现在商业Java虚拟机大多采用这种算法进行收集,IBM曾进行过统计,新生代的百分之98的对象都熬不多第一次收集,因此不必用1:1比例来划分空间。
理论进阶(HotSpot使用的)
“Appel 回收”:Appel式回收把新生代分为一块较大的Eden空间和两块较小的Survivor空间,每次分配内存只使用Eden和其中一块Survivor。
过程:发生垃圾收集时,将Eden和Survivor中仍存活的对象一次性复制到另外一块Survivor上,然后清理Eden和已使用的Survivor。当Survivor空间不足以容纳一次Minor GC之后的存活对象,就需要老年代进行分担。
4. 标记-整理算法
标签:在对象存活率较高时就要进行较多的复制操作,效率会更低,对标记-清除算法的一种改进。
过程:发生垃圾收集时,将存活的对象标记,然后清除回收未标记的对象,然后再进行排序。
优点:合理利用空间,内存空间划分规整。
缺点:在进行整理的时候,会暂停对象的分配,我们称之为“stop the world”。