JVM垃圾回收机制篇

垃圾回收算法

1> 引用计数法

  • 增加引用 +1,失去引用 -1
  • 存在循环引用问题
  • JVM未选择此算法作为垃圾回收算法

2> 标记清除法

image.png

  • 分为“标记”和“清除”两个阶段
  • 标记:从根节点开始判断,存在引用标记为存活对象
  • 清除:清除所有没有被标记的对象

缺点:产生大量的空间碎片

适用场景:老年代

3> 复制算法

image.png

  • 将内存空间分为两块
  • 标记存活的对象,将存活的对象复制移动到另外一块内存(B内存)空闲面上面,清除未存活对象(A内存)
  • 缺点:系统内存只能使用1/2,需要复制移动对象

适用场景:年轻代

4> 标记压缩法

image.png

  • 标记存活的对象,将所有存活的对象压缩到内存的一端,然后在清理所有存活对象之外的空间

5> 分区算法

image.png

  • 将堆空间划分成连续的不同小区间,每个区间独立使用、回收
  • 由于当堆空间大时,一 次GC的时间会非常耗时,那么可以控制每次回收多少个小区间

6> 分代回收算法

把堆分为新生代 和 老年代

  • 新生代:
    • Eden - S0 - S1 划分比例为 8:1:1
    • 回收频率高耗时短
    • 标记复制
  • 老年代
    • 回收频率低耗时高
    • 标记压缩算法
    • 标记清除算法 CMS

优势:对于新生代中使用标记复制算法,可以使用的空间为 Eden + S0 = 8 + 1 = 90%


新生代垃圾回收

  • Eden + S0 内存不足,就会触发GC(Minor gc/young gc),这时就会根据 GC Roots 标记存活对象,把存活对象复制到 S1,此时存活对象年龄加1,清除 Eden + S0 未存活的对象 。
  • GC后S0区域被清空。S0和S1发生了互换,S1变成了From Survivor,S0变成了To Survivor(To Survivor区永远都为空)

老年代垃圾回收

  • 随着年轻代对象的不断晋升,老年代的对象变得越来越多,达到容量阈值后老年代也会发生垃圾回收,我们称之为Major GC或者Full GC,Full GC并不是全局GC,它只发生在老年代。

晋升机制

  • 设置 OldObject -XX:MaxTenuringThreshold=15
    • 每经历一次gc存活的对象分代年龄+1达到15进入老年代
  • 设置 BigObject -XX:PretrnureSizeThreshold=0 大对象直接进入 老年代
    • 如果参数被设置成5MB,超过5MB的大对象会直接分配到老年代
    • 注意:PretenureSizeThreshold参数只对Serial和ParNew两种回收器有效
  • 动态对象年龄判定
    • Survivor空间中相同年龄对象大小的总和大于Survivor空间的一半,以及相比它年龄更大的对象都会被晋升到老年代