「JVM 内存管理」GC 评估与选择

最先进的 GC 并不是满足所有应用场景的 GC,要因地制宜,按需选择;

1. Epsilon GC

一个不干活的 GC;

一个垃圾收集器除了垃圾收集之外,内存的管理与布局、对象分配、与解释器的协作、与编译器的协作、与监控子系统协作等也是必须关注的内容;从 JDK 10 开始,为了隔离垃圾收集器与 JVM 解释、编译、监控等子系统的关系,RedHat 提出了垃圾收集器的统一接口,Epsilon 是这个接口的有效性验证和参考实现,同时也用于需要剥离垃圾收集器影响的性能测试和压力测试(对比效果);

如果应用只运行数分钟甚至数秒,只要 JVM 能正确分配内存,在 Heap 耗尽之前退出,那运行负载极小、没有任何回收行为 的 Epsilon 是很恰当的选择;

2. 选择 GC 的考虑因素

  • 应用程序的主要关注点(停顿时间、吞吐量、内存占用),SLA 应用关注停顿时间,数据分析等后台任务关注吞吐量(计算速度),小型嵌入式或客户端应用的内存占用不可忽视;
  • 运行应用的基础设施条件(硬件规格、性能,系统平台等);
  • JDK 版本(OracleJDK、OpenJDK、ZingJDK/Zulu、OpenJ9 等);

3. VM 及 GC 日志

HotSpot 从 JDK 9 开始通过 -Xlog 管理 VM 日志(此前的日志设置是各 GC 独立解决);

-Xlog[:[selector][:[output][:decorators][:output-options]]]
  • selector(选择器),有标签(Tag,功能模块的名称,垃圾收集器的标签名是 gc)和日志级别(Level,决定了日志输出的详细程度,默认 Info 级别)共同组成;
    • Tag: add,age,alloc,annotation,aot,arguments,attach,barrier,biasedlocking,blocks,bot,breakpoint,bytecode 等;
    • Level: Trace,Debug,Info,Warning,Error,Off;
  • decorators(修饰器),为每行日志输出附加额外内容,如 pid、tid、level、tags、time、uptime、timemillis、uptimemillis、timenanos、uptimenanos(默认是:uptime、level、tags);
# eg.
[3.080s][info][gc,cpu] GC(5) User=0.03s Sys=0.00s Real=0.01s

JDK 9 前后日志参数对比

JDK 9 前日志参数JDK 9 后配置形式
G1PrintHeapRegionsXlog:gc+region=trace
G1PrintRegionLivenessInfoXlog:gc+liveness=trace
G1SummarizeConcMarkXlog:gc+marking=trace
G1SummarizeRSetStatsXlog:gc+remset*=trace
GCLogFileSize,NumberOfGCLogFiles,UseGCLogFileRotationXlog:gc*:file=::filecount=,filesize=
PrintAdaptiveSizePolicyXlog:gc+ergo*=trace
PrintClassHistogramAfterFullGCXlog:classhisto*=trace
PrintClassHistogramBeforeFullGCXLog:classhisto*=trace
PrintGCApplicationConcurrentTimeXlog:safepoint
PrintGCApplicationStoppedTimeXlog:safepoint
PrintGCDateStamps使用 time 修饰器
PrintGCTaskTimeStamps使用 uptime 修饰器
PrintHeapAtGCXlog:gc+heap=debug
PrintHeapAtGCExtendedXlog:gc+heap=trace
PrintJNIGCStallsXlog:gc+jni=debug
PrintOldPLABXlog:gc+plab=trace
PrintParallelOldGCPhaseTimesXlog:gc+phases=trace
PrintPLABXlog:gc+plab=trace
PrintPromotionFailureXlog:gc+promotion=debug
PrintReferenceGCXlog:gc+ref=debug
PrintStringDeduplicationStatisticsXlog:gc+stringdedup
PrintTaskqueueXlog:gc+task+stats=trace
PrintTenuringDistributionXlog:gc+age=trace
PrintTerminationStatsXlog:gc+task+stats=debug
PrintTLABXlog:gc+tlab=trace
TraceAdaptiveGCBoundaryXlog:heap+ergo=debug
TraceDynamicGCThreadsXlog:gc+task=trace
TraceMetadataHumongousAllocationXlog:gc+metaspace+alloc=debug
G1TraceConcRefinementXLog+gc+refine=debug
G1TraceEagerReclaimHumongousObjectsXlog:gc+humongous=debug
G1TraceStringSymbolTableScrubbingXlog:gc+stringtable=trace

获取 GC 信息日志示例

  • 查看 GC 基本信息
# JDK 9 之前
-XX:+PrintGC
# JDK 9 后
java -Xlog:gc GCTest
  • 查看 GC 详细信息
# JDK 9 之前
-XX:+PrintGCDetails
# JDK 9 后
java -Xlog:gc* GCTest
  • 查看 GC 前后的 Heap、Method Area 可用容量变化
# JDK 9 之前
-XX:+PrintHeapAtGC
# JDK 9 后
java -Xlog:gc+heap=debug GCTest
  • 查看 GC 过程中用户线程并发时间和停顿时间
# JDK 9 之前
-XX:+PrintGCApplicationConcurrentTime -XX:+PrintGCApplicationStoppedTime
# JDK 9 后
java -Xlog:safepoint GCTest
  • 查看收集器 Ergonomics 机制自动调节(堆分代大小、收集目标等调节)的信息
# JDK 9 之前
-XX:+PrintAdaptiveSizePolicy
# JDK 9 后
java -Xlog:gc+ergo*=trace GCTest
  • 查看 GC 后存活对象的年龄分布
# JDK 9 之前
-XX:+PrintTenuringDistribution
# JDK 9 后
java -Xlog:gc+age=trace GCTest

4. GC 参数汇总

参数说明
UseSerialGCVM 在 Client 模式下的默认值,开启此开关,将使用 Serial + Serial Old 的 GC 组合进行内存回收
UseParNewGC打开此开关,将使用 ParNew + Serial Old 的 GC 组合进行内存回收,JDK 9 后不在支持
UseConcMarkSweepGC打开此开关,将使用 ParNew + CMS + Serial Old 的 GC 组合,Serial Old 作为 CMS 出现 Concurrent Mode Failure 失败后的后备 GC
UseParallelGC打开此开关,将使用 Parallel Scavenge + Serial Old 的 GC 组合,JDK 9 之前 Server 模式的默认选项
UseParallelOldGC打开此开关,将使用 Parallel Scavenge + Parallel Old 的 GC 组合
SurvivorRatio新生代中 Eden:Survivor 的容量比值,默认是 8,表示 Eden:Survivor = 8:1
PretenureSizeThreshold直接晋升老年代的对象大小,大于这个参数的对象将直接在老年代分配
MaxTenuringThreshold晋升老年代的对象年龄,每 Minor GC 一次,对象的年龄加 1,超过这个参数值时,对象进入老年代
UseAdaptiveSizePolicy动态调整 Java Heap 中各区域的大小,以及晋升老年代的年龄
HandlePromotionFailure是否允许分配担保失败,即老年代的剩余空间不足以应付新生代整个 Eden 和 Survivor 的所有对象都存活的情况
ParallelGCThreads(STW 期间,)给并行 GC 设置 GC 线程个数
GCTimeRatioGC 时间占总时间的比率,默认 99,表示 1/(1+99) 的时间可用于 GC,仅对 Parallel Scavenge 有效
MaxGCPauseMillis设置 GC 最大停顿时间 仅对 Parallel Scavenge 有效
CMSInitiatingOccupancyFraction设置 CMS 在老年代空间被用多少后触发 GC,默认 68%,仅对 CMS 有效
UseCMSCompactAtFullCollection设置 CMS 在完成 GC 后是否进行一次碎片整理,仅对 CMS 有效,JDK 9 废弃
UseG1GC使用 G1 GC,JDK 9 后成为默认选项
G1HeapRegionSize=n设置 Region 大小,并非最终值
MaxGCPauseMillis设置 G1 GC 的停顿目标时间,默认 200ms,不是强制时间限制
G1NewSizePercent设置 G1 新生代最小值,默认 5%
G1MaxNewSizePrecent设置 G1 新生代最大值,默认 60%
ConcGCThreads=n并发标记,并发整理的执行线程数,不同 GC 的不同阶段含义可能不同
InitiatingHeapOccupancyPercent设置触发标记周期的 Java Heap 占用率阈值,默认 45%,这里的占比指 non_young_capacity_bytes(old+humongous)
UseShenandoahGC使用 Shenandoah GC,需要与 -XX:+UnlockExperimentalVMOptions 使用,仅对 OpenJDK 12 以上或支持的 Backport 版本有效,对 OracleJDK 无效
ShenandoahGCHeuristicsShenandoah 合适启动一次 GC,可选项为 adaptive、static、compact、passive、aggressive
UseZGC使用 ZGC,在 JDK 15 前需要配合 -XX:+UnlockExperimentalVMOptions 使用
UseNUMA启用 NUMA 内存分配支持,只支持 Parallel 和 ZGC,G1 在后续也可能支持

上一篇:「JVM 内存管理」2 款低延迟的 GC
下一篇:「JVM 内存管理」内存分配与回收策略

PS:感谢每一位志同道合者的阅读,欢迎关注、评论、赞!


参考资料:

  • [1]《深入理解 Java 虚拟机》
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Aurelius-Shu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值