JVM调优-解决native heap持续增长

问题的提出,分析,请参考JNI——小心,内存怪兽出没

(简单的说起来,就是java进程占用了4G内存,但是折腾来折腾去,整个JVM的堆才100M上下,其余的内存凭空消失?刨根问底之后,原来是native heap占用了内存)

看完上面的问题,再来看解决方案:

 

 

 

目前看来,通过调整 JVM 参数来加大 GC 触发的频率是比较现实的一种方式。下面是一些分析过程:

 

一.       判断 Memonry 内存所属的区


JVM调优-解决native heap持续增长

通过 jconsole 可以看到 gc 信息,其中新生代的 scavenge 回收比较频繁,如果 Memonry 在这个区应该不存在长期得不到 gc 的情况

由此推测 Memory 应该是在 Tenured/old ,而这个区的内存回收次数恰好非常少。 当然参数优化的目标,就是加大 old 区的 gc 频率。

 

二.       观察 JVM 的堆参数配置

1. 默认配置下,堆的分配起始值为 126M ,最大 1.8G  


JVM调优-解决native heap持续增长

 

2. 观察 gc 前后 java 整个堆 的使用情况, gc 前大概占 130M, 远未达到默认设置下的内存容量


JVM调优-解决native heap持续增长

 

3. 进一步查看 old 区的内存 ,发现在 gc 前稳定在 90M

而默认参数初始分配 85M ,最大 1.3G ,显然很难触发到 GC


JVM调优-解决native heap持续增长

 

三.       解决问题

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。
JVM调优-解决native heap持续增长

下面看看GC的情况: MarkSweep是old区的gc策略,大概2个小时会触发一次,每次耗时

3194/112=28.5178ms,不会对应用产生明显的停摆,并且也验证了MaxGCPauseMillis参数的作用


 JVM调优-解决native heap持续增长

 

你可能感兴趣的:(jvm,数据结构,配置管理,jni)