为什么要介绍这个工具? {#%E4%B8%BA%E4%BB%80%E4%B9%88%E8%A6%81%E4%BB%8B%E7%BB%8D%E8%BF%99%E4%B8%AA%E5%B7%A5%E5%85%B7%EF%BC%9F}
GC日志是一个很重要的数据,它准确记录了每一次的GC的执行时间和执行结果,通过分析GC日志可以优化堆设置和GC设置,或者改进应用程序的对象分配模式。
GCEasy是什么? {#gceasy%E6%98%AF%E4%BB%80%E4%B9%88%EF%BC%9F}
业内首款借助机器学习技术引导的垃圾回收日志分析工具。GCeasy 内置有智能功能,可自动检测 JVM 和 Android GC 日志中的问题并推荐解决方案,推荐解决方案是付费功能。
GCEasy怎么使用?让我们来看个例子 {#gceasy%E6%80%8E%E4%B9%88%E4%BD%BF%E7%94%A8%EF%BC%9F%E8%AE%A9%E6%88%91%E4%BB%AC%E6%9D%A5%E7%9C%8B%E4%B8%AA%E4%BE%8B%E5%AD%90}
- 首先要开启应用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%E6%97%A5%E5%BF%97%E6%8A%A5%E5%91%8A%E5%8C%85%E5%90%AB%E5%93%AA%E4%BA%9B%E6%8C%87%E6%A0%87%E5%88%86%E6%9E%90%EF%BC%9F}
常见的一些GC问题 {#%E5%B8%B8%E8%A7%81%E7%9A%84%E4%B8%80%E4%BA%9Bgc%E9%97%AE%E9%A2%98}
对象过早晋升 {#%E5%AF%B9%E8%B1%A1%E8%BF%87%E6%97%A9%E6%99%8B%E5%8D%87}
一、现象:
- 老年代使用率增长过快,每次Full GC后老年代使用率呈现断崖式下跌,Minor GC 和 Full GC都比较频繁。
- 老年代空间占用量统计(通过gc日志统计):
二、影响: - Young GC 频繁,总的吞吐量下降。
- Full GC 频繁,可能会有较大停顿。
三、原因:
年轻代(主要是eden区)过小: - eden区无法容纳足够多的年轻对象,造成young gc的次数增加。
- 本应该在年轻代就回收的对象却晋升到了老年代,加快了老年代的占用速度,造成full gc的次数增加。
四、优化: - 增大新生代空间,降低minor gc和major gc的频率,减少系统STW的时间、提高系统的吞吐量。
对象晋升失败 {#%E5%AF%B9%E8%B1%A1%E6%99%8B%E5%8D%87%E5%A4%B1%E8%B4%A5}
一、场景:
- young gc过程中,To Survivor空间不足以放下eden + from Survivor中存活的对象,故这些存活的对象只能尝试着晋升到老年代中,若此时老年代的内存也不足以放下这些对象,则晋升失败(promotion failed),此时,老年代会进行full gc。
二、优化: - 适当地调大Survivor空间,尽量避免朝生夕灭的对象进入老年代。
- 使用标记整理算法收集,及时整理老年代中的内存碎片,避免因内存碎片太多导致大对象晋升失败:
- 开启老年代内存压缩:-XX:UseCMSCompactAtFullCollection
- 每次cms gc时都进行内存压缩:XX:CMSFullGCBeforeCompaction=0
并发收集失败 {#%E5%B9%B6%E5%8F%91%E6%94%B6%E9%9B%86%E5%A4%B1%E8%B4%A5}
一、场景:
- 场景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)