调优过程
操作步骤
- 下载demo程序,打包部署参照README.md。
- 对程序进行在线分析,切换到GC页签。在浏览器调用接口“http://{ip}:9118/gctest/bigdata”,需多次访问。图1 GC页签-1
发现有些GC原因是巨型对象的分配造成的。
- 对程序进行采样分析,切到GC页签。
查看优化建议报告。
图2 GC页签-优化建议 - 采样分析切换到内存页签的老年代对象页面。
采样分析时需在浏览器多次调用接口“http://{ip}:9118/gctest/bigdata”。
图3 老年代对象在某些情况下,如果巨型对象的生命周期比较长,则在该页签下可以采集到对象的相关信息,也会得到一份报告,可以得知巨型对象大小,还可以知道当前程序的region大小,根据相关信息,可以得出结论采集的巨型对象是在同一个线程中创建的,巨型对象为6Mib大小的int[],可以根据堆栈搜索代码,看看具体的逻辑。
- 在线分析执行内存转储。如果通过采样分析不能直接采集到巨型对象,可以通过得知的region大小,可从堆转储分析中找相应的线索。在直方图中找堆占用较多的嫌疑类。图4 内存转储
- 查看每个嫌疑类的所有对象。图5 内存转储图6 列出所有对象
发现频繁分配了int[],大小为6Mib,符合巨型对象要求,继续定位。
- 支配树查找线索。图7 支配树
支配树中发现一个线程保留堆大小跟直方图中int[]的保留堆大小差不多。
图8 支配树展开展开发现这个线程中有个List持有创建的巨型对象,查看从int[]到GC Roots的路径。
图9 从int[]到GC Roots的路径入口 - 程序代码定位。
根据在线分析提供的类名:GcTestController ,巨型对象为int[], List持有巨型对象等线索,直接找到具体的代码。
图10 demo - 优化后的Java程序。
本demo通过设置调大region大小的方式解决该问题。
图11 概览页签图12 GC页签
总结
本次实践中,通过采样分析和堆转储分析定位代码中具体巨型对象分配的位置,以调大region的大小解决。但是在实际的业务中,优先建议调整代码逻辑去解决问题,尽量避免分配巨型对象,从而减轻jvm的压力。如果发现默认的region大小不符合程序的体量,可以根据实际情况适当调大region的大小。
在进行其他程序调优时,需要根据鲲鹏DevKit Java性能分析工具采集的实际结果和对应的优化建议进行调优操作,具体的调优思路可以参考本次实践。
父主题: 实践5:G1巨型对象触发GC调优实践