# Java GC

最近业务上遇到频繁gc和gc长的问题。单一个月出现了两次gc超过30s的问题。

本着解决问题的目标,温习和系统地看一下java gc的策略,温故而知新,看下怎么优化。

# Ergonomics

Ergonomics是JVM的垃圾回收调优器,用来提高应用性能。

https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/ergonomics.html

对于并行收集器来说,Java SE基于行为调优,提供了里那个黄总垃圾回收调优参数:最大停顿时间和应用吞吐量。(只适用于Parallel Collector)

# Maximum Pause Time Goal

-XX:MaxGCPauseMillis=<nn>垃圾回收器会调整heap size和其它回收参数来尽量保证停顿时间小于设置的时间。

# Throughput Goal

-XX:GCTimeRetio=<nnn>吞吐量指垃圾回收时间和应用的其他时间的比值。计算为1/1+(<nn>)

垃圾回收时间包括年轻代和老年代。如果吞吐量不满足,对应的分代的大小会被提高。

# Footprint Goal

如果最大停顿时间和吞吐量目标都符合预期,那么垃圾回收器会减少堆大小直到有一个目标不被满足(一般是吞吐量),然后再调整。

几种调优策略:

  • 如果堆达到最大值,吞吐量不满足,那么扩大最大堆限制。
  • 吞吐量满足了,但是最大停顿时间过长,那么选择最大停顿时间目标。

# 分代

一般常用的垃圾回收器都是分代的。这里不过多记录。

虚拟机默认会调整堆大小来让每个分代收集的活动对象保持特定范围。

参数 默认值
MinHeapFreeRatio 40
MaxHeapFreeRatio 70
-Xms 6656k
-Xmx calculated

Client端默认最大堆为物理内存的一半不超过192MB。否则超过这个数则为物理内存的1/4。超过1GB内存按照256MB算。 Server端和Client端一样,但是限制放宽。32-bit JVMs默认最大堆可以在4GB物理内存下达到1GB。再64-bit JVMs中默认最大32GB。

参数 Server JVM默认值
NewRatio 2
NewSize 1310M
MaxNewSize not limited
SurvivorRatio 8

NewRetio=2指年轻代和老年代比例1:2。 SurvivorRatio=8指年轻代中的Eden区和Survivor区的比例1:8。

# 常用垃圾收集器(GC Collector)

Java HotSpot VM有三种不同的垃圾收集器。

  • 串行收集器。Serial Collector。单线程完成所有的收集工作。没有线程间通讯开销,在单核机器下表现最好。默认在对应的操作系统或硬件上,或者设置:-XX:+UseSerialGC
  • 并行收集器。Parallel Collector(throughput collector),并行处理minor collections。可以显著减少垃圾回收的负载。适合中等或大型数据集,运行在多核或多线程机器上。默认在对应的操作系统和硬件上,或者设置:-XX:+UseParallelGC。并行压缩是一项使并行收集器能够并行执行major collections的功能。如果没有并行压缩,major collections使用单个线程执行,这可能会显著限制可扩展性。如果指定了选项-XX:+UseParallelGC,则默认启用并行压缩。关闭它的选项是-XX:-UseParallelOldGC
  • 大多数并发收集器都在同时执行其他操作的时候收集。例如应用正在运行的时候,为了让垃圾暂停时间短。在中等或大型数据集,响应时间要求大于吞吐要求的场景。因为并行收集器的场景尽可能减少应用暂停的影响。最常用的两种并行收集器:-XX:+UseConcMarkSweepGC来开启CMS收集器或者-XX:+UseG1GC来开启G1收集器。

# 垃圾收集器选择

以下小技巧仅供参考。实际影响因素还有很多。

  • 如果引用数据集小于100MB,选择串行收集器。-XX:+UseSerialGC
  • 单核或者没有暂停时间要求,让VM自己选择收集器,或者使用串行收集器。-XX:+UseSerialGC
  • 如果(a)峰值应用程序性能是第一优先级,并且(b)没有暂停时间要求或可以暂停1秒或更长时间,则让虚拟机选择收集器,或使用-XX:+UseParallelGC选择并行收集器。
  • 如果响应时间比整体吞吐量更重要,并且垃圾收集暂停必须缩短到约1秒,则选择具有-XX:+UseConcMarkSweepGC-XX:+UseG1GC的并发收集器。

# 参考

  • https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/introduction.html#sthref3
  • https://tech.meituan.com/2020/11/12/java-9-cms-gc.html
  • https://tech.meituan.com/2017/12/29/jvm-optimize.html