JVM调优-解决native heap持续增长
来源:互联网 发布:按键精灵 js 插件 编辑:程序博客网 时间:2024/06/05 07:58
问题的提出,分析,请参考JNI——小心,内存怪兽出没
(简单的说起来,就是java进程占用了4G内存,但是折腾来折腾去,整个JVM的堆才100M上下,其余的内存凭空消失?刨根问底之后,原来是native heap占用了内存)
看完上面的问题,再来看解决方案:
目前看来,通过调整JVM参数来加大GC触发的频率是比较现实的一种方式。下面是一些分析过程:
一. 判断Memonry内存所属的区
通过jconsole可以看到gc信息,其中新生代的scavenge回收比较频繁,如果Memonry在这个区应该不存在长期得不到gc的情况
。由此推测Memory应该是在Tenured/old区,而这个区的内存回收次数恰好非常少。 当然参数优化的目标,就是加大old区的gc频率。
二. 观察JVM的堆参数配置
1.默认配置下,堆的分配起始值为126M,最大1.8G。
2.观察gc前后java整个堆的使用情况,gc前大概占130M,远未达到默认设置下的内存容量
3.进一步查看old区的内存,发现在gc前稳定在90M。
而默认参数初始分配85M,最大1.3G,显然很难触发到GC。
三. 解决问题
1. 首要的问题就是控制JVM 对整个heap的大小分配:
-Xmx300M 指定jvm的最大heap大小,
-Xms40M 指定jvm的最小heap大小,
2.在减小了整个堆的前提下,优化 NewRatio这个参数(指定jvm中Old Generation heap size与New Generation的比例)
将默认的NewRatio=2更改为更符合业务实际内存使用比例的 -XX:NewRatio=1
减小了old 区的比例,更容易触发gc。
3. 另外一个猜测的可行方案:(有待验证)
启用jvm中的gc参数 -XX:MaxGCPauseMillis=<nnn>
这个参数的大概含义就是,让每次gc的时间不超过参数nnn 。那么nn减少的时候,必然会增加到gc的次数,来换取每次gc的速度。
通过下图的数据可以求出,每次old区的gc平均耗时34.7ms, 那么可以 -XX:MaxGCPauseMillis=28 ,也许会增加到gc频率。
上述4个标红参数已经添加,观察几天得到的结论是,比较好的解决了这个问题。
====================================================================
分割线:下面是调优后的观察:
可以看到整个内存呈波动结构,Java的堆从20M--》60M就触发一次old区的gc。
下面看看GC的情况: MarkSweep是old区的gc策略,大概2个小时会触发一次,每次耗时
3194/112=28.5178ms,不会对应用产生明显的停摆,并且也验证了MaxGCPauseMillis参数的作用