一次12G堆dump的分析

背景

生产环境一个系统偶尔出现卡顿的情况,于是拿到线上环境的jvm配置和堆dump信息。

堆内存配置

堆内存配置分析

堆的总内存是12G年轻代478M年老代11.5G永久代最小512M,最大1G年轻代与年老代的比=1:25,这个比例也是很惊人的,默认比例是2,也就是三分天下,年轻代占一,年老代占二。SurvivorRatio1024,代表Eden区一个Surivor区=1024。所以From SpaceTo Space都只有43.75KB


为何会出现如此小的Survivor区呢,小的跟没有一样了,看参数发现配了这么个参数:-XX:MaxTenuringThreshold=0,这个代表年轻代的对象经历多少次GC,如果还活着就会放到年老代,结果这儿配成了0,那意思就是只要在Minor GC后活着,就放到年老代。这样的话,Survivor区确实就没啥用了。

和调整参数的同事沟通,但是他们调整的原因是:

一次12G堆dump的分析-LMLPHP


但是这样的话不就会出现年老代一直累积,累积到七八个G,然后来一把Full GC吗,本来很多对象是可以朝生暮死的,但是我们一直攒着,让它苟活于世。很容易导致Full GC时的长STW(stop the world)。

一次12G堆dump的分析-LMLPHP

一次12G堆dump的分析-LMLPHP

堆dump信息分析

通过MAT工具分析dump的堆信息,存在以下问题

1.unreachable object很多,占了4个G左右,有很多是由Artery框架生成的表单控件,由于在第一次MinorGC时还活着,就放到老年代了。可以考虑能否优化框架代码,对象重用。

一次12G堆dump的分析-LMLPHP

2.缓存内容太多,动不动就是几十上百M。针对这些大缓存,需要考虑命中率,考虑LRU,减少对象。

一次12G堆dump的分析-LMLPHP

3.hibernate用的太随意,产生了大量无用对象。4.字符串占用了两个多G,java9是提供了字符串压缩功能,可以节约1半的内存。



一次12G堆dump的分析-LMLPHP

其他

待后续改进后,再发布进展情况。to be continued...

参考资料

https://docs.oracle.com/javase/9/gctuning/concurrent-mark-sweep-cms-collector.htm#JSGCT-GUID-4CB5DCEB-FCBF-4A57-83A1-F2C47BF0B3D7


本文分享自微信公众号 - 程序员阿水(gh_124d28263603)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

09-08 05:07
查看更多