JVM垃圾收集器

一、Serial(串行)收集器

  • 针对新生代采用“复制”算法,老年代采用“标记-整理”算法。
  • 属于单线程收集器,垃圾收集时,必须暂停其他所有的工作线程(又称为「Stop The World」),但这几十毫秒的停顿,对于客户机(client)来说是完全可以接受的,是client级别的默认GC方式;同时由于是单线程,没有线程交互的开销,因此可以获得最高的单线程收集效率。

二、ParNew 收集器

  • 只针对新生代采用“复制”算法。
  • Serial 收集器的多线程版本,并行进行垃圾回收,主要用于服务器端(server),除了 Serial 收集器外,只有它能与 CMS 收集器配合工作。

三、Parallel Scavenge(并行清除)收集器

  • 只针对新生代采用“复制”算法。
  • 和ParNew 收集器差不多,但其特别之处在于参数设置:

-XX:+UseParallelGC:新生代Parallel Scavenge收集器+老年代Serial Old 收集器(“标记-整理”算法);

-XX:+UseParallelOldGC:新生代Parallel Scavenge收集器+老年代Parallel Old 收集器(“标记-整理”算法);

  • 能够高效利用CPU,实现可控制的吞吐量,适合于多CPU的应用。

四、CMS (Concurrent Mark Sweep)收集器

  • 采用“标记-清除”算法。
  • 运作过程:
  1. 初始标记:暂停所有其他线程,仅仅只是标记一下 GC Roots 能直接关联到的对象,速度很快;
  2. 并发标记:同时开启 GC 和用户线程,进行 GC Roots 追溯所有对象的过程,在整个过程中耗时最长;
  3. 重新标记:这个阶段也要暂停所有其他线程,是为了修正并发标记期间因为用户程序继续运行而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间一般会比初始标记阶段的时间稍长,远远比并发标记阶段时间短;
  4. 并发清除:开启用户线程,同时GC线程开始对未标记的区域做清除;

      JVM垃圾收集器

  • 优点:并发收集,停顿时间少。
  • 缺点:对CPU资源非常敏感;无法处理浮动垃圾;同时由于采用的是“垃圾-清除”算法,故也会产生大量空间碎片。

五、G1 (Garbage-First)收集器

  • 空间整合:整体上是基于“标记-整理”算法,从局部来看是基于“复制”算法;保留了分代回收的概念。
  • 运作过程:
  1. 初始标记:暂停所有其他线程,仅仅只是标记一下 GC Roots 能直接关联到的对象,速度很快;
  2. 并发标记:同时开启 GC 和用户线程,进行 GC Roots 追溯所有对象的过程,在整个过程中耗时最长;
  3. 重新标记:这个阶段也要暂停所有其他线程,是为了修正并发标记期间因为用户程序继续运行而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间一般会比初始标记阶段的时间稍长,远远比并发标记阶段时间短;
  4. 筛选回收:G1将整个Java堆划分为多个大小相等的内存块(Region),每个Region 是逻辑连续的一段内存,在后台维护一个优先列表,每次根据允许的收集时间,优先回收垃圾最多的区域;
  • G1 相对于 CMS来说具有两大优势,第一个是基于“标记-整理”算法,不会产生空间碎片;第二个是能建立可预测的停顿时间模型,让使用者明确指定在一个长度为 M 毫秒的时间片段内进行垃圾收集。

PS:

并行:指多条垃圾收集线程并行工作,但此时用户线程仍然处于等待状态。

并发:指用户线程与垃圾收集线程同时执行(但不一定是并行,可能会交替执行),用户程序在继续运行,而垃圾收集器则运行在另一个 CPU 上。

浮动垃圾:CMS并发清除阶段用户线程还在运行,这段时间就有可能产生新的垃圾,新的垃圾在此次GC将无法清除,只能等到下次清理。