垃圾收集算法

       垃圾收集算法可以划分为:引用计数式垃圾收集和追踪式垃圾收集两大类,这两类也常被称为直接垃圾收集和间接垃圾收集。

分代收集理论

       分代收集名为理论,实质是一套符合大都数程序运行实际情况的经验法则,它建立在两个分代假说之上:

弱分代假说(Weak Generational Hypothesis):绝大多数对象都是朝生夕灭的。

强分代假说(Strong Generational Hypothesis):熬过越多次垃圾收集过程的对象就越难以消亡。

虚拟机采用分区的方式进行垃圾回收,根据熬过垃圾回收的次数分配到不同的区域中,好处是垃圾收集的时间短和内存的空间利用率高。

JDK7以前:新生代,老年代,永久代

JDK7以后:新生代,老年代,元空间

标记-清除算法

        分为两个阶段:标记、清除,首先需要标记出所有需要回收的对象,在标记完成后,统一回收掉所有被标记的对象,也可以反过来,标记存活的对象,统一回收未被标记的对象。标记过程就是对象是否属于垃圾判定的过程。如果对象在进行可达性分析后发现没有与GC Roots相连接的引用链,那它将会被第一次标记,随后进行一次筛选,筛选的条件是此对象是否有必要执行finalize()方法。假如对象没有覆盖finalize()方法,或者finalize()方法已经被虚拟机调用过,那么虚拟机将这两种情况都视为没有必要执行。如果这个对象被判定确有必要执行finalize()方法,那么该对象将会被放置到一个名为F-Queue队列中,并在稍后由一条虚拟机自动建立的,低优先级的Finalizer线程去执行(执行:触发开始运行方法,并不会等待方法执行结束,原因是如果某个对象的finalize()方法执行缓慢或者有死循环,将可能导致F-Queue队列中的其他对象永久处于等待,甚至导致整个内存回收子系统的崩溃)它们的finalize()方法。finalize()方法是对象逃脱死亡命运的最后一次机会,稍后收集器将对F-Queue中的对象进行二次小规模标记,如果对象要在finalize()方法中拯救自己-只要重新与引用链上的任何一个对象建立连接即可,在第二次标记时它将被移出“即将回收”的集合,如果该对象还没有被引用,那基本上就真的要被回收了。finalize()方法只会被系统自动调用一次。

优点:速度快

缺点:

  • 执行效率不稳定,如果Java堆中包含大量对象,而且其中大部分是需要被回收的,这时必须进行大量标记和清除的动作,导致标记和清除两个过程的执行效率都随对象数量增长而降低。
  • 内存空间碎片化,标记、清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致当以后再程序运行过程中需要分配较大对象时无法找到足够连续的内存而不得不提前触发另一次垃圾收集动作。

标记-复制算法

        为了解决清除算法面对大量可回收对象时执行效率低的问题,1969年Fenichel提出了一种称为“半区复制”的垃圾收集算法,它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块内存用完了,就将还存活的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。如果内存中多数对象都是存活的,这种算法将会产生大量的内存间复制的开销,但对于多数对象都是可回收的情况,算法需要复制的就是占少数的存活对象,而且每次都是针对整个半区进行内存回收,分配内存时也就不用考虑有空间碎片的复杂情况,只要移动堆顶指针,按顺序分配即可。

优点:实现简单,运行高效,不会产生内存碎片

缺点:可用内存空间为原来的一半,内存空间浪费

       在1898年,Andrew Appel针对具备“朝生夕灭”特点的对象,提出了一个更优化的半区复制分代策略,现在称为“Appel式回收”。具体做法是把新生代分为一块较大的Eden空间和两块较小的Survivor空间(默认比例为8:1:1),每次分配内存只使用Eden和其中一块Survivor。发生垃圾收集时,将Eden和Survivor中仍然存活的对象一次性复制到另外一块Survivor空间上,然后直接清理掉Eden和已用过的那块Survivor空间。 新生代中可用内存空间为整个新生代容量的90%,Eden 80%加上一个Survivor 10%。当Survivor空间不足以容纳一次Minor GC之后存活的对象时,就需要依赖其他内存区域(实际上大多就是老年代)进行分配担保。分配担保后续还会讲(3.8.5)

标记-整理算法

       标记复制算法在对象存活率较高时要进行较多的复制操作,效率会降低。如果不想浪费50%的内存空间,就需要有额外的空间进行担保。

       1974年Edward Lueders提出了标记-整理算法,其中的标记过程仍然与标记清除算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向内存空间一端移动,然后直接清理掉边界以外的内存。

        标记-清除算法与标记-整理算法的本质差异在于前者是一种非移动式的回收算法,而后者是移动式的。是否移动回收后的存活对象是一项优缺点并存的风险决策:如果移动存活对象,尤其是在老年代这种每次回收有大量对象存活区域,移动存活对象并更新所以引用这些对象的地方将会是一种极为负重的操作,而且这种对象移动操作必须全程暂停用户应用程序才能进行,这就更加让使用者不得不小心翼翼权衡其弊端了,像这样的停顿被最初的虚拟机设计者形象地描述为“Stop The World”。 

优点:不会产生内存碎片

缺点:速度慢,效率低(地址重排)

        也有收集器采用标记清除算法与标记整理算法相结合的方式,先采用标记清除算法,暂时容忍内存碎片化,直到内存碎片空间的碎片化程度大到影响对象分配时,在采用标记整理算法收集一次,以获得规整的空间。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值