深入理解Java虚拟机:垃圾收集算法





一. 分代收集理论

1)弱分代假说(Weak Generational Hypothesis):绝大多数对象都是朝生夕灭的。
2)强分代假说(Strong Generational Hypothesis):熬过越多次垃圾收集过程的对象就越难以消亡。

从以上2个假说上,演化出了新生代和老年代,但是当老年代引用了新生代的对象的时候,就会导致新生代对象无法回收。此时就需要去除了遍历新生代对象还要遍历老年代对象进行回收,这样就会浪费大量时间。针对于这个问题。引入了第三个假说。

3)跨代引用假说(Intergenerational Reference Hypothesis):跨代引用相对于同代引用来说仅占极少数。

这时,标识出老年代的哪一块内存会存在跨代引用。然后收集扫描某个内存模块。




二. 按照(新生代、老年代)GC区域进行划分

部分收集

  • 新生代收集 Minor GC/Young GC : 目标只是新生代的垃圾收集。
  • 老年代收集 Major GC/Old GC : 目标只是老年代的垃圾收集。
  • 混合收集 Mixed GC : 指目标是收集整个新生代以及部分老年代的垃圾收集。

整体收集

  • Full GC :收集整个Java堆和方法区的垃圾收集。



三. 垃圾收集算法

标记-清除算法 (老年代通常使用)

顾名思义,算法分为“标记”和“清除”两个阶段。
以下代码是引用了《深入理解Java虚拟机》第三版 图3-2 “标记-清除”算法示意图
在这里插入图片描述
算法缺陷:

  1. 首先如果当内存中有大量的对象需要回收,这是必须进行大量的标记和清除动作,并且这个操作的执行效率会随着对象的增多而下降。
  2. 内存碎片化,以上图为例,这样回收完的内存会有大量的碎片化,无法得到一个连续的内存,导致提前出发另一次垃圾收集动作。

适用区域的要求:

  1. 所以使用的时候要保证这个区域并不是有大量的对象需要回收,减少标记和清除的动作。
  2. 并且减少碎片化的可能

标记-整理算法 (老年代 当内存空间的碎片化程度已经大到影响对象分配时)

当对象存活率较高的时候使用“标记-复制算法”,会有大量的复制操作,效率将会降低,更关键的是如果不想分割出另一半内存,就需要另外拿出空间做分配担保保,以应对被使用的内存中所有对象都100%存活的极端情况。很明显这里(老年代)使用“标记-复制算法”是很不明智的。
所以我们使用了一种先标记,然后然后清理,再把存活的对象一起想内存空间一端移动。
以下代码是引用了《深入理解Java虚拟机》第三版 图3-4 “标记-整理”算法示意图
在这里插入图片描述
由于如果老年代每次都是使用“标记-整理算法”,大量的空间移动会使得“Stop The World”,但是如果每次都使用“标记-清除算法”又会形成大量的内存碎片,最终影响整个程序的吞吐量。

一种中和的解决方案

做法是让虚拟机平时多数时间都采用标记-清除算法,暂时容忍内存碎片的存在,直到内存空间的碎片化程度已经大到影响对象分配时,再采用标记-整理算法收集一次,以获得规整的内存空间。前面提到的基于标记-清除算法的CMS收集器面临空间碎片过多时采用的就是这种处理办法。


标记-复制算法 (新生代通常使用,通过Eden和Survivor的配合)

为了解决“标记-清除算法”回收对象效率低的问题。提出了一种“半区复制”的垃圾收集算法。将内存划分为等量的两块,比如新生代中的2个幸存者Survivor区域,标记后将不需要回收的对象直接放入另一个半内存中,解决了内存碎片化的问题。并且清除掉当前内存中的被标记对象。
以下代码是引用了《深入理解Java虚拟机》第三版 图3-3 “标记-复制”算法示意图

在这里插入图片描述
由于新生代中大量的对象都无法活过第一轮回收,因此不需要使用一分为二的方式去分割新生代。而选用了一个伊甸园二个幸存者的方式,来分割。一般使用3:1:1的比例。

标记-复制算法流程

  1. 大量对象存入伊甸园Eden中,当伊甸园中达到某个百分比时,使用第一次“标记-复制算法”回收,(当标记的是不清除对象时)将大量未标记对象进行清除,少量标记对象进入其中一个空的Survivor区域(此时另一个Survivor内存也是空的)。
  2. 再有大量对象存入伊甸园Eden中,使用第二次“标记-复制算法”回收,(当标记的是不清除对象时)将大量未标记对象进行清除,但是此时少量标记对象和Survivor(非空)中的对象一起复制到另一个Survivor(为空)中,并且清理掉之前用过的那块Survivor内存。
  3. 当经历多次操作2后,不为空的Survivor空间不足以容纳一次Minor GC之后存活的对象时,就需要依赖老年代进行分配担保。

举例银行担保人借钱

内存的分配担保好比我们去银行借款,如果我们信誉很好,在98%的情况下都能按时偿还,于是银行可能会默认我们下一次也能按时按量地偿还贷款,只需要有一个担保人能保证如果我不能还款时,可以从他的账户扣钱,那银行就认为没有什么风险了。






如有错误欢迎指正
参考文献《深入理解Java虚拟机》第三版

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一只小小狗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值