深入理解JVM——分代收集理论及垃圾收集算法

分代收集理论

分代收集理论的三条假说

(1)弱分代假说:绝大多数对象都是朝生夕灭的。
(2)强分代假说:熬过越多此垃圾收集过程的对象就越难以消亡。
(3)跨代引用假说:跨代引用相对于同代引用来说只占极少数(存在相互引用关系的两个对象,是应该趋向于同时生存或同时消亡的)。

强分代假说和弱分代假说奠定了多款常用垃圾收集器的一致原则:

收集器将 Java 堆分成不同的区域,然后将回收的对象依据其年龄分配到不同的区域之中存储。区域中大多数对象生命周期都很短时在回收时只需关注如何保留少量存活的对象,这个区域中的个别对象经过多次垃圾回收都存活后可以将其存入普遍生命周期都很长的区域,以较低的频率进行此部分的垃圾回收。

跨代引用问题:

只需在新生代上建立一个全局的数据结构(记忆集),这个结构把老年代划分为若干个小块,标识出老年代哪一块内存会存在跨代引用。此后当发Minor GC时,只有包含了跨代引用的小块里的内存才会被加入到 GC Roots 中进行扫描。
缺点:需要在对象改变引用关系时维护记录数据的正确性。
优点:收集时无需扫描整个老年代。

垃圾收集算法

标记-清除算法

(1)算法分为标记和清除两个阶段。
(2)缺点主要有两个,一是执行效率不稳定,如果 Java 堆中有大量对象是需要回收的,那必须进行大量的标记和清除动作,导致标记和清除两个动作的执行效率都随对象数量的增长而降低。二是内存空间的碎片化问题,标记、清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致当以后在程序运行过程中需要分配较大对象时无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。

标记-复制算法

(1)将可用的内存按容量分为大小相等的两块,每次只使用其中的一块,当这一块用完后就将还活着的对象复制到另一块上,然后再把已使用过的空间一次清理掉。此算法适用于内存中的对象存活率比较低的情况,比如新生代。
(2)优点:分配时不需考虑有内存碎片的情况,只需要移动堆顶指针按顺序分配即可,实现简单,运行高效。缺点:缩小了内存空间的利用率。
(3)现存的商用 Java 虚拟机大多都使用这种方法实现新生代的回收。
(4) Appel 式回收:对半区复制的优化策略。HotSpot 虚拟机的 Serial、ParNew 等新生代收集器均采用了这种策略来设计新生代的内存布局。具体做法是把新生代划分成一块较大的Eden空间和两块较小的Survivor空间,每次内存分配只使用Eden和其中一块Survivor。发生垃圾搜集时,将 Eden 和 Survivor 中依然存在的对象一次性复制到另一块 Survivor 空间中,然后直接清理掉 Eden 和已经使用过的那块 Survivor 区域。Eden 和两块 Survivor 区域的默认比例是 8:1:1。当 Survivor 空间不足以容纳一次 Minor GC 之后存活的对象时就需要依赖其他的内存区域进行分配担保。

标记-整理算法

(1)标记过程与标记-清除算法一样,但后续操作不是 直接对可回收对象进行清理,而是让所有存活的对象都向内存空间的一端移动,然后直接清理掉边界以内的内存。
(2)如果移动老年代这种每次回收都有大量对象存活的区域会是一种极为负重的操作,并且这种移动必须全程暂停用户应用程序才能进行(Stop The World)。
(3)HotSpot 虚拟机中关注吞吐量的 Parallel Scavenge 收集器是基于标记-整理算法的(如果跟标记-清除算法那样完全不考虑移动和整理存活对象的话,弥散于堆中的存活对象导致的空间碎片化问题就只能依赖更为复杂的内存分配器和内存访问器来解决,势必会直接影响应用程序的吞吐量),而关注延迟的 CMS 收集器则是基于标记-清除算法。另外还有第三种折中的方法是让虚拟机平时采用标记-清除算法,暂时容忍内存碎片的存在,直到内存空间的碎片化程度已经大到影响对象分配时,再采用标记-整理算法收集一次,以获得规整的内存空间,CMS 算法面临空间碎片过多是采用的就是这种处理办法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值