分类

  1. Minor GC(年轻代垃圾回收):
    • 针对年轻代(Young Generation)进行垃圾回收
    • 当年轻代满时触发(通常由Eden区满、S0或S1区满触发)
    • 垃圾对象相对较少,停顿时间较短。存活对象会被移到年老代。
  2. Major GC(主要垃圾回收):
    • Major GC 这个术语在Java中并不是一个官方的术语,有时也被用来指代Full GC。
    • 有时人们使用 “Major GC” 来表示一次垃圾回收中涉及老年代的部分,即Full GC中清理老年代的过程。
  3. Full GC(完全垃圾回收或老年代垃圾回收):
    • 针对整个堆(包括年轻代和老年代)进行垃圾回收。
    • 当年轻代和老年代都满时触发,也可能由永久代(jdk7)满触发。
    • 清理的范围更广,涉及整个堆。通常停顿时间相对较长。

垃圾回收算法

标记-清除算法(Mark and Sweep)

  • 标记阶段: 从根节点开始,通过可达性分析标记所有能够被访问到的对象。
  • 清除阶段: 通过遍历整个堆,清除未被标记的对象,即垃圾对象。
  • 优点: 简单,容易实现。不需要移动对象。
  • 缺点: 产生内存碎片。 暂停时间较长。

复制算法(Copying)

  • 将堆分为两个区域,每次只使用其中一个。将存活的对象从一个区域复制到另一个区域。清理当前区域的所有对象。
  • 优点: 无内存碎片。适用于小对象,存活对象较少的场景(新生代)。
  • 缺点: 需要额外的空间。需要复制对象,移动开销较大。

标记-整理算法(Mark and Compact)

  • 标记可达对象,将存活对象向一端移动,然后清理未标记的区域。
  • 优点: 无内存碎片。相较于复制算法,减少了对象复制的开销。
  • 缺点: 移动对象可能导致引用更新的复杂性。暂停时间相对较长。

分代回收算法(Generational):

  • 将堆分为年轻代和老年代。大部分对象在年轻代被快速回收,少部分晋升到老年代。
  • 优点: 利用了对象的生命周期不同的特性,针对不同年代使用不同的垃圾回收策略。
  • 缺点: 需要额外的管理。不能解决所有的垃圾回收问题。

垃圾回收器

  1. Serial Garbage Collector:(串行垃圾回收器)
    • 单线程执行,适用于小型应用或测试环境。
  2. Parallel Garbage Collector:
    • 多线程执行,充分利用多核处理器。
    • 在新生代使用并行垃圾回收器,老年代使用串行垃圾回收器。
  3. Concurrent Mark-Sweep (CMS) Garbage Collector:
    • 主要用于老年代的垃圾回收。
    • 在标记和清理阶段允许与应用程序线程并发执行,目标是最小停顿时间
  4. Garbage First(G1) Garbage Collector:
    • 适用于大堆内存,具有低停顿时间的需求。
    • 将堆划分为多个区域(region),通过并行和并发阶段实现垃圾回收。

CMS

四阶段:初始标记,并发标记,重新标记,并发清除
其中第一、三阶段需要STW(stop the world,暂停用户线程)

  1. 初始标记:标记所有直接被GCroot关联的对象,速度比较快
  2. 并发标记:从GC Roots的直接关联对象开始遍历整个对象图的过程,耗时较长,但是是并发执行,不需要暂停用户线程
  3. 重新标记:修正并发标记期间,因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,需要STW,但时间不会太长
  4. 并发清除:清理删除掉标记阶段判定的已经死亡的对象,释放内存空间,不需要移动存活对象,可以与用户线程同时并发(产生内存碎片)
    由于最耗费时间的并发标记与并发清除阶段都是不需要暂停用户线程的,所以整体的回收是低停顿的

G1

回收步骤与CMS相似,初始标记,并发标记,最终标记,筛选回收
重要概念和特点:

  1. 区域(region):把堆内存分割为很多不相关的区域(Region)(物理上不连续),所有region均可以用来当作eden,survivor,old,humongous(存储大对象)(区域化内存布局
  2. Region之间是复制算法(从若干个rigion回收融合到一个region),但整体上实际可看作是标记-整理算法
  3. G1除了追求低停顿外,还能建立可预测的停顿时间模型,能让使用者明确指定在一个长度为M毫秒的时间片段内,消耗在垃圾收集上的时间不得超过N毫秒(可预测停顿时间),因为会优先回收价值高的region(垃圾优先
  4. 可以只选取部分区域进行内存回收,这样缩小了范围,因此对于全局停顿情况的发生也能得到较好的控制,可以进行混合回收,同时处理新生代和老年代
  5. 并行和并发执行垃圾回收操作,并行加快标记和复制的速度,并发减少垃圾回收对应用程序的停顿时间

补充

关于GC root

GCroot(垃圾收集根)是指一组对象,这些对象被认为是在垃圾收集时安全的,不会被垃圾收集器回收。垃圾收集根是整个对象图的起始点,垃圾收集器通过这些根对象能够追踪到其他对象的引用链,从而确定哪些对象是可达的,哪些是不可达的,进而进行垃圾回收。
以下是一些常见的 GCroot 类型:

  1. 栈中的局部变量和输入参数:
    • 方法中的局部变量和输入参数,以及调用方法时传递的参数,都是GCroot。这是因为它们是程序执行的起点。
  2. 静态变量(类变量):
    • 存储在静态变量中的对象也是GCroot,因为它们随着类的加载而存在,不依赖于特定的实例。
  3. JNI 引用:
    • 通过 Java Native Interface (JNI) 创建的引用,允许 Java 代码访问和调用本地库的接口。JNI 引用也是 GCroot。
  4. 活动的线程:
    • 正在运行的线程本身也是 GCroot,因为它们持有一些对象的引用,而这些引用不能被垃圾收集。
  5. Finalizer 引用:
    • 当一个对象的finalize()方法被调用时,这个对象是 GCroot,因为在finalize()方法中可能会重新建立对象的引用关系。