文章收录在网站:http://hardyfish.top/
文章收录在网站:http://hardyfish.top/
文章收录在网站:http://hardyfish.top/
文章收录在网站:http://hardyfish.top/
垃圾收集算法
分代收集理论
当前商业虚拟机的垃圾收集器,大多数都遵循了分代收集(Generational Collection)的理论进行设计,它建立在两个分代假说之上:
弱分代假说(Weak Generational Hypothesis):
- 绝大多数对象都是朝生夕灭的
强分代假说(Strong Generational Hypothesis):
- 熬过越多次垃圾收集过程的对象越难以消亡
这两个分代假说共同奠定了多款常用的垃圾收集器的一致设计原则:
- 收集器应该将Java堆划分出不同的区域,
- 然后将回收对象依据其年龄(年龄即对象熬过垃圾收集过程的次数)分配到不同的区域之中存储
- 显而易见,如果剩下的都是难以消亡的对象,那就把它们集中放在一起
- 虚拟机便可以使用较低的频率来回收这个区域,这就同时兼顾了垃圾回收的时间开销和内存空间的有效利用
- 在Java堆划分出不同的区域之后,垃圾收集器才可以每次只回收其中某一个或者某些部分的区域——因而才有了
Minor GC
Major GC
,Full GC
这样的回收类型的划分
- 也才能够针对不同的区域安排与里面存储对象存亡特征相匹配的垃圾收集算法——因而展示出了:
- 标记-复制算法,标记-清除算法,标记-整理算法等针对性的垃圾收集算法
跨代引用假说(
Intergenerational Reference Hypothesis
):跨代引用相对于同代来说仅占极少数
- 这其实是可根据前两条假说逻辑推理得出的隐含推论:
- 存在互相引用关系的两个对象,是应该倾向于同时生存或者同时消亡的
- 例如,如果某个新生代对象存在跨代引用,由于老年代对象难以消亡
- 该引用会使得新生代对象在收集时同样得以存活,进而在年龄增大之后晋升到老年代中,这时跨时代引用也随即被消除了
对于不同分代的名词定义:
- 部分收集(Partial GC):指目标不是完整收集整个Java堆的垃圾收集,其中又分为:
- 新生代收集(Minor GC/Yong GC):
- 指目标只是新生代的垃圾收集
- 老年代收集(Major GC/Old GC):
- 指目标只是老年代的垃圾收集
- 混合收集(Mixed GC):指目标是收集整个新生代以及部分老年代的垃圾收集
- 目前只有GI收集器会有这种行为
- 整堆收集(Full GC):收集整个Java堆和方法区的垃圾收集
标记-清除算法
标记-清除算法是最基础的垃圾收集算法,该算法分为标记和清除两个阶段:
- 首先标记出所有需要回收的对象,在标记完成后,统一回收掉所有被标记的对象
- 也可以反过来,标记存活的对象,统一回收所有未被标记的对象。标记过程就是对象是否属于垃圾的判定过程
该算法有两个缺点:
- 执行效率不稳定,如果Java堆中包含大量对象,而且其中大部分是需要回收的,这时必须进行大量标记和清除的动作
- 导致标记和清除两个过程的执行效率都随对象数量增长而降低
- 内存空间的碎片化问题,标记、清除之后会产生大量不连续的内存碎片
- 空间碎片太多可能会导致当以后再程序运行过程中需要分配较大对象时无法找到足够的连续内存而不得不提前触发另一次垃圾收集算法
标记-复制算法
标记-复制算法常被称为复制算法,为了解决标记-清除算法面对大量可回收对象时执行效率低的问题
- 该算法将可用内存按容量划分为大小相等的两块,每次只使用其中的一块
当这一块用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用的内存空间一次清理掉
标记-整理算法
标记-整理算法标记的过程仍然与标记-清除算法一样,但后续步骤不是直接对可回收对象进行清理
- 而是让所有存活的对象都向内存空间一端移动,然后直接清理掉边界以外的内存
标记-清理算法与标记-整理算法的本质差异在于前者是一种非移动式的回收算法,而后者是移动式的