写点什么

理解 JVM 工作机制(五)垃圾回收算法

作者:ue4
  • 2023-05-24
    上海
  • 本文字数:1197 字

    阅读完需:约 4 分钟

垃圾回收算法

垃圾分代收集

部分收集(Partial GC):指目标不是完整收集整个 Java 堆的垃圾收集,其中又分为:


  • 新生代收集(Minor GC/Young GC): 指目标只是新生代的垃圾收集。

  • 老年代收集(Major GC/Old GC): 指目标只是老年代的垃圾收集。目前只有 CMS 收集器会有单独收集老年代的行为。


另外请注意“Major GC”这个说法现在有点混淆,在不同资料上常有不同所指,读者需按上下文区分到底是指老年代的收集还是整堆收集。


  • 混合收集(Mixed GC): 指目标是收集整个新生代以及部分老年代的垃圾收集。目前只有 G1 收集器会有这种行为。

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

标记-清除


在 Java 堆中标记需要清除的对象并执行清除


这是最基本的算法。 分两个步骤


  • 标记(Mark)过程:遍历所有的 GC Roots,然后将所有 GC Roots 不可达的对象标记成不可存活的对象

  • 清除(Swep)过程:清除的过程将遍历堆中所有的对象,将标记的对象全部清除掉


标记清除的过程


标记-复制

为了解决效率问题,一种称为“复制”(Copying)的收集算法出现了,它将可用内存按容量划分为大小相等的两块,每次只使用其中的一一块。当这一块的内存用完了 ,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。这样使得每次都是对整个半区进行内存回收,内存分配时也就不用考虑内存碎片等复杂情况,只要移动堆顶指针,按顺序分配内存即可,实现简单,运行高效


优点:避免内存碎片


缺点:对堆内存造成了浪费,可用内存缩小了一半


优化方案 (Apple 式回收):


将内存分为三块: Eden、From Survivor、To Survivor,比例是 8:1:1,每次使用 Eden 和其中一块 Survivor。回收时,将 Eden 和 Survivor 中还存活的对象一次性复制到另外一块 Survivor 空间上,最后清理掉 Eden 和刚才使用的 Survivor 空间。这样只有 10% 的内存被浪费。


但是我们无法保证每次回收都只有不多于 10% 的对象存活,当 Survivor 空间不够,需要依赖其他内存(指老年代)进行分配担保。


分配担保


为对象分配内存空间时,如果 Eden+Survivor 中空闲区域无法装下该对象,会触发 MinorGC 进行垃圾收集。但如果 Minor GC 过后依然有超过 10% 的对象存活,这样存活的对象直接通过分配担保机制进入老年代,然后再将新对象存入 Eden 区。

标记-整理

标记:它的第一个阶段与标记/清除算法是一模一样的,均是遍历 GC Roots,然后将不可达的对象标记。


整理:移动所有存活的对象,且按照内存地址次序依次排列,然后将末端内存地址以后的内存全部回收。因此,第二阶段才称为整理阶段。


这是一种老年代的垃圾收集算法。老年代的对象一般寿命比较长,因此每次垃圾回收会有大量对象存活,如果采用复制算法,每次需要移动大量存活的对象,效率很低。

分代收集算法

根据对象存活周期的不同,将内存划分为几块。一般是把 Java 堆分为新生代和老年代,针对各个年代的特点采用最适当的收集算法。


  • 新生代:复制算法

  • 老年代:标记-清除算法、标记-整理算法

发布于: 刚刚阅读数: 3
用户头像

ue4

关注

还未添加个人签名 2020-08-26 加入

还未添加个人简介

评论

发布
暂无评论
理解JVM工作机制(五)垃圾回收算法_Java_ue4_InfoQ写作社区