垃圾回收器

Serial 回收器 串行回收器

https://tva1.sinaimg.cn/large/007S8ZIlly1gewnwf8vbfj30rj05fjtl.jpg

是一个单线程工作的收集器,但它的“单线 程”的意义并不仅仅是说明它只会使用一个处理器或一条收集线程去完成垃圾收集工作,更重要的是强 调在它进行垃圾收集时,必须暂停其他所有工作线程,直到它收集结束。

Serial收集器是HotSpot中Client模式下的默认新生代垃圾收集器

Serial 收集器采用复制算法、串行回收和”Stop- the-World”机制的方式执行内存回收。

除了年轻代之外,Serial收集器还提供用于执行老年代垃圾收集的Serial old收集器,Serial Old收集器同样也采用了串行回收和”Stop the World”机制, 只不过内存回收算法使用的是标记-压缩算法。

  • Serial old是运行在Client模式下默认的老年代的垃圾回收器
  • Serial old在Server模式下主要有两个用途
    • 与新生代的Parallel Scavenge配合使用
    • 作为老年代CMS收集器的后备垃圾收集方案.

优点:

​ 单而高效(与其他收集器的单线程相比),对于内存资源受限的环境,它是所有收集器里额外内存消耗(Memory Footprint)最小的;对于单核处理 器或处理器核心数较少的环境来说,Serial收集器由于没有线程交互的开销,专心做垃圾收集自然可以 获得最高的单线程收集效率。

​ 在用户桌面的应用场景以及近年来流行的部分微服务应用中,分配给虚 拟机管理的内存一般来说并不会特别大,收集几十兆甚至一两百兆的新生代(仅仅是指新生代使用的 内存,桌面应用甚少超过这个容量),垃圾收集的停顿时间完全可以控制在十几、几十毫秒,最多一 百多毫秒以内,只要不是频繁发生收集,这点停顿时间对许多用户来说是完全可以接受的。

总结:

在限定单核CPU才使用。

ParNew 回收器 并行回收器

https://tva1.sinaimg.cn/large/007S8ZIlly1gewnw0u2zlj30ru05m415.jpg

new 指新生代区域中进行回收

ParNew收集器实质上是Serial收集器的多线程并行版本,收集算法、Stop The World、对象分配规 则、回收策略等都与Serial收集器完全一致 。

Parallel Scavenge 回收器 吞吐量优先

https://tva1.sinaimg.cn/large/007S8ZIlly1gewnvoothwj30sn05igob.jpg

运行在 新生代区域, 同样采用复制算法,并行回收, STW 机制, 目标是达到一个可控制的吞吐量(处理器用于运行用户代码的时间与处理器总消耗时间的比值)。

高吞吐量适合:后台运算, 不需要交互时间的任务

Parallel Old

Parallel Scavenge 回收器的 老年代版本。使用标记-压缩算法, 基于并行回收 和 STW 机制

参数配置

  • -XX : ParallelGCThreads 设置年轻代并行收集器的线程数,最好与CPU数相等,避免影响性能
  • -XX:MaxGCPauseMillis 控制最大垃圾收集停顿时间, 即STW最大时间
  • -XX:GCTimeRatio 设置吞吐量大小,垃圾收集时间占总时间的比例 1 / ( N + 1), 默认是 99, 垃圾回收时间不超过1%

CMS 回收器 低延迟

https://tva1.sinaimg.cn/large/007S8ZIlly1gewnridt3xj30rp05f789.jpg

Concurrent Mark Sweep 是一种以获取最短回收停顿时间为目标的收集器, 通常都会较为关注服务的响应速度,希望系统停顿时间尽可能短,以给用户带来良好的交互体验。

基于标记-清除算法, STW机制

  1. 初始标记(CMS initial mark) 初始标记仅仅只是标记一下GC Roots能直接关联到的对象,速度很快。 需要 STW
  2. 并发标记(CMS concurrent mark) 从GC Roots的直接关联对象开始遍历整个对象图的过程,这个过程耗时较长但是不需要停顿用户线程,可以与垃圾收集线程一起并发运行
  3. 重新标记(CMS remark) 修正并发标记期间,因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间通常会比初始标记阶段稍长一些,但也远比并发标记阶段的时间短 需要STW
  4. 并发清除(CMS concurrent sweep) 清理删除掉标记阶段判断的已经死亡的对象,由于不需要移动存活对象,所以这个阶段也是可以与用户线程同时并发的。

CMS 特点

  • 最耗时的并发标记与并发清除阶段不需要 STW, 整体回收是低停顿的。
  • 另外,由于在垃圾收集阶段用户线程没有中断,所以在CMS回收过程中,还应该确保应用程序用户线程有足够的内存可用。因此,CMS收集器不能像其他收集器那样等到老年代几乎完全被填满了再进行收集,而是当堆内存使用率达到某一 阈值时,便开始进行回收,以确保应用程序在CMS工作过程中依然有足够的空间支持应用程序运行。要是CMS运行期间预留的内存无法满足程序需要,就会出现一次“Concurrent Mode Failure”失败,这时虚拟机将启动后备预案:临时启用Serial old收集器来重新进行老年代的垃圾收集,这样停顿时间就很长了。
  • 使用标记-清除算法, 清理完成后内存是不连续的碎片, 无法使用指针碰撞, 只能使用 空闲列表 进行内存分配。

缺点

  • 会产生内存碎片,导致并发清除后,用户线程可用的空间不足。在无法分配大对象的情况下,不得不提前触发Full GC。
  • CMS 收集器对CPU资源非常敏感。在并发阶段,它虽然不会导致用户停顿,但是会因为占用了一部分线程而导致应用程序变慢,总吞吐量会降低。
  • CMS收集器无法处理浮动垃圾。可能出现“Concurrent Mode Failure” 失败而导致另一次Full GC的产生。在并发标记阶段由于程序的工作线程和垃圾收集线程是同时运行或者交叉运行的,那么在并发标记阶段如果产生新的垃圾对象,CMS将无法对这些垃圾对象进行标记,最终会导致这些新产生的垃圾对象没有被及时回收,从而只能在下一次执行GC时释放这些之前未被回收的内存空间。

参数设置

  • -XX:CMSInitiatingOccupancyFraction 设置堆内存使用率的阈值,达到阈值后开始回收
    • 如果内存增长缓慢,可以设置较大值,降低CMS 触发频率, 减少老年代的回收次数
    • 如果内存使用率增长快速,则降低阈值,避免频繁触发老年代串行回收器
    • 改选项可以有效降低 Full GC 次数
  • -XX:+UseCMS-CompactAtFullCollection 在CMS收集器 Full GC 时开启内存碎片的合并整理过程, 避免内存碎片。但是停顿时间更长
  • -XX:CM SFullGCsBeforeCompaction (JDK 9 废弃) CMS收集器在执行过若干次不整理空间的Full GC之后,下一次进入Full GC前会先进行碎片整理

总结

最小化内存和并行开销:Serial GC

最大化程序吞吐量: Parallel GC

最小化 GC 中断、停顿时间:CMS GC

https://tva1.sinaimg.cn/large/007S8ZIlly1gexttohjjyj31i80dq7wh.jpg

选择

  • 优先调整堆的大小让JVM自适应完成。
  • 如果内存小于100M,使用串行收集器
  • 如果是单核、单机程序,并且没有停顿时间的要求,串行收集器
  • 如果是多CPU、需要高吞吐量、允许停顿时间超过1秒,选择并行或者JVM自己选择
  • 如果是多CPU、追求低停顿时间,需快速响应(比如延迟不能超过1秒,如互联网应用),使用并发收集器 官方推荐G1,性能高。现在互联网的项目基本都是使用G1。