为什么要介绍这个工具?
GC日志是一个很重要的数据,它准确记录了每一次的GC的执行时间和执行结果,通过分析GC日志可以优化堆设置和GC设置,或者改进应用程序的对象分配模式。
GCEasy是什么?
业内首款借助机器学习技术引导的垃圾回收日志分析工具。GCeasy 内置有智能功能,可自动检测 JVM 和 Android GC 日志中的问题并推荐解决方案,推荐解决方案是付费功能。
GCEasy怎么使用?让我们来看个例子
- 首先要开启应用GC日志,关于开启GC日志命令有很多可选参数,这里不细讲,可以参考:https://blog.csdn.net/lazycheerup/article/details/100917193
本次使用以下命令演示:
java -XX:+PrintGCDetails -Xloggc:/opt/ard-user-gc-%t.log -jar spring-boot-demo-0.0.1-SNAPSHOT.jar
- 将应用产生的GC上传到https://gceasy.io/
点击“分析”,等待分析结果。
- GC分析报告支持下载和分享连接。
GC日志报告包含哪些指标分析?
常见的一些GC问题
对象过早晋升
一、现象:
- 老年代使用率增长过快,每次Full GC后老年代使用率呈现断崖式下跌,Minor GC 和 Full GC都比较频繁。
- 老年代空间占用量统计(通过gc日志统计):
二、影响: - Young GC 频繁,总的吞吐量下降。
- Full GC 频繁,可能会有较大停顿。
三、原因:
年轻代(主要是eden区)过小: - eden区无法容纳足够多的年轻对象,造成young gc的次数增加。
- 本应该在年轻代就回收的对象却晋升到了老年代,加快了老年代的占用速度,造成full gc的次数增加。
四、优化: - 增大新生代空间,降低minor gc和major gc的频率,减少系统STW的时间、提高系统的吞吐量。
对象晋升失败
一、场景:
- young gc过程中,To Survivor空间不足以放下eden + from Survivor中存活的对象,故这些存活的对象只能尝试着晋升到老年代中,若此时老年代的内存也不足以放下这些对象,则晋升失败(promotion failed),此时,老年代会进行full gc。
二、优化: - 适当地调大Survivor空间,尽量避免朝生夕灭的对象进入老年代。
- 使用标记整理算法收集,及时整理老年代中的内存碎片,避免因内存碎片太多导致大对象晋升失败:
- 开启老年代内存压缩:-XX:UseCMSCompactAtFullCollection
- 每次cms gc时都进行内存压缩:XX:CMSFullGCBeforeCompaction=0
并发收集失败
一、场景:
- 场景1:CMS GC期间,业务线程将对象放到老年代,若此时老年代空间不足,则会导致CMS并发收集失败(Concurrent Mode Failure)。
- 场景2:CMS GC期间,若某次young gc过程中发生了promotion failed,则也会导致CMS并发收集失败。
- CMS并发收集失败发生后,由于老年代空间不足,需要尽快回收老年代里面的不再被使用的对象,这时jvm会停止所有的应用线程,同时终止CMS收集,直接进行Serial Old来收集。
二、现象: - stop the world持续时间比较长,系统持续(十几秒甚至几分钟)无响应。
三、优化: - 在业务低峰时段提前触发full gc。
没有开启-XX:+DisableExplicitGC的前提下调用System.gc()就会发生FullGC - 降低触发CMS GC的阈值,保障老年代有足够的空间。
开启根据阈值触发CMS GC开关:-XX:+UseCMSInitiatingOccupancyOnly
设置触发CMS GC的阈值:-XX:CMSInitiatingOccupancyFraction=xx (默认是92)