JVM垃圾回收

286 阅读5分钟

JVM垃圾回收

什么是垃圾?怎么判断对象可以被回收?

垃圾是指程序不再使用,并且后续也不会访问的对象。

根可达性算法

判断对象是否可以被回收。

首先找出一系列的GC Root根对象:

  • 系统类的实例对象
  • 本地方法调用相关的实例对象
  • 当前活动线程相关的实例对象
  • 被加锁的实例对象

以GC Root为起点,沿着引用链进行查找,能找到的对象不可回收,不在GC Root引用链上的对象就是需要回收的对象。

垃圾回收算法

标记-清除算法

算法分为标记和清除两个阶段,首先标记所有需要回收的对象,在标记完成之后统一回收被标记的对象。

缺点: 会产生内存碎片,需要维护一个空闲列表给对象分配内存空间。

标记整理算法

算法分为标记和整理两个阶段,首先标记所有需要回收的对象,标记完成之后让所有存活的对象向一端移动,然后直接清除另一端的所有对象。

适合存活对象多,垃圾较少的场景。

优点: 不会产生内存碎片。

缺点: 整理阶段需要暂停所有活动程序线程,效率低。

复制算法

将内存一分为二,1区存放对象 标记需要回收的对象,在1区快满了后,将不需要回收的对象复制到2区,然后清除1区内存。

适合存活对象少,垃圾对象多的场景。

优点:

  • 复制后保证空间的连续性,不会出现内存碎片。

缺点:

  • 需要两倍的内存空间。
  • 复制,需要GC维护对象的引用关系,内存占用、时间开销大。

分代垃圾回收

堆内存分为新生代和老年代,新生代分为Eden区和两个Survivor区(From、To)。

新生代存生命周期短的对象,老年代存大对象或者生命周期长的对象。

新生代

  • 大部分对象都会在Eden区生成。
  • Eden空间不足时,触发一次Minor GC,使用复制算法 将存活对象从Eden区复制到To区 对象寿命+1,清除Eden区,将From和To交换 From区保留存活对象。
  • 类似,每次新对象在Eden区生成,Eden区内存空间不足时,就会触发Minor GC,使用复制算法,将Eden区和From区的存活对象复制到To 并寿命+1,清除Eden区,交换From和To,From保留存活对象。
  • Minor GC会一直重复这个过程,直到To区填满。

老年代

  • To区填满,所有对象移动到老年代。
  • 存活对象寿命超过阈值,说明生命周期长,非常重要,需要转移到GC不频繁的老年代。
  • 大对象会直接进入老年代,不触发GC。
  • 老年代空间不足,会先尝试Minor GC清除新生代,如果空间依然不足,会尝试Full GC清除老年代。

注意

  • Minor GC和Full GC都会触发SWT暂停所有活动线程,垃圾回收完成后,其他线程才能执行。Full GC暂停时间更长。
  • Full GC后空间仍然不足,会抛出Out Of Memory error。

垃圾回收器

CMS

CMS是老年代并行垃圾处理器,使用标记清除算法,并发收集垃圾,追求最短GC回收停顿时间。

回收过程:

  • 初始标记 STW

    标记所有GC Roots能直接关联到的对象,不需要对引用链全部扫描。

  • 并发标记 不需要STW

    对初始标记阶段标记的对象 进行整个引用链的扫描,标记所有可达的对象,用户线程并发运行。

  • 重新标记 STW

    GC和用户线程并发运行,速度快,但会产生漏标和多标的问题。对并发标记阶段出现的问题进行矫正。

  • 并发清除 不需要STW

    清除未标记的垃圾。

优点:

  • 切分引用链扫描的过程,GC线程和用户线程并发执行,重新标记矫正问题,减少垃圾回收的时间。

缺点:

  • 多线程并发执行,cpu占用高。
  • CMS并发清理中,用户进程并发执行,会有漏标、多标的情况,产生浮动垃圾。
  • 标记清除算法会产生内存碎片。

G1

G1垃圾回收器将堆划分为多个大小相等的region,垃圾回收以region为基本单位。整体上是标记整理算法,两个region之间是复制算法。

G1垃圾回收器同时注重吞吐量和低延迟,默认的暂停目标是200ms。

垃圾回收过程:

  • 初始标记 STW

    标记GC Roots可以直接关联的对象。

  • 并发标记 不需要STW

    从初始标记阶段标记的对象出发,遍历整个堆里的对象图,标记所有可达的对象。用户线程并发运行。

  • 最终标记 STW

    处理并发标记阶段,用户线程工作 导致引用变化的对象。

  • 筛选回收 STW

    • 先对region的回收价值进行排序,然后根据期望暂停时间,选择性回收region。
    • 不追求一次性清理完所有垃圾,优先回收垃圾最多的region。
    • 回收使用复制算法,复制存活对象到空region,清空原region。