一探究竟-跟踪G1老年代晋升对象

2023-11-25  本文已影响0人  yuanjian

背景

    现网服务频繁YGC,每次YGC都会有对象晋升老年代,造成频繁混合回收。但是程序中接口执行很快,平均响应时长在10ms,理论上不该产生老年代对象。
    到底什么对象在晋升?如果能够定位晋升对象,我们就可以对程序做进一步的优化,下面我们来介绍在G1垃圾收集器中如何快速定位YGC后晋升到老年代中的对象。

实践

环境:java11

java版本
  1. 启动脚本增加参数: -XX:+UseG1GC -Xlog:gc*,region*=trace:./gc.log:time

  2. 在程序进行混合回收前打DUMP
        注意:建议在打印dump前先压缩gc日志,否则dump后产生的GC日志可能会影响排查过程。

  3. 查找有老年代对象晋升的YGC
    通过脚本grep "Old regions:" gc.log查看 old region变化

    对象晋升情况

    发现第24次GC有大量对象晋升

  4. 对象晋升一定会分配新的老年代分区,使用命令查询第24次GC老年代的分配情况

    命令:grep 'GC(24)' gc.log | grep 'ALLOC(OLD)',用于查找第24次GC分配的老年代分区。

老年代分区分配情况
  1. 我们根据内存地址查询第24次GC的分配和使用情况

    命令:grep 'GC(24)' gc.log | grep '0x00000007c3200000'

    分区使用情况

    图中可发现此region从F变为了O(空闲region转变为老年代region),表示有对象晋升到此region。region地址:0x00000007c3200000,0x00000007c3300000
    我们可以使用相同的方法查看其它region的晋升情况,并找到晋升的内存地址。
    注意:[] 中的三个16进制数,分别为region的起始地址、当前已使用到的地址、结束地址

  1. 使用MAT工具打开DUMP文件,并使用OQL根据region地址进行查找

    命令:SELECT * FROM INSTANCEOF java.lang.Object t WHERE toHex(t.@objectAddress)>="0x7c3300000" AND toHex(t.@objectAddress)<="0x7c3400000"

image-20231122232859764.png

注意:查找条件中的内存地址需要将前面连续的0去掉。

上一篇下一篇

猜你喜欢

热点阅读