一、自动生成Dump(JMX的MBean)
JVM启动参数配置:
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/home/app/dumps/
二、手动生成Dump
jmap -dump:format=b,file=../dump/testdump0329.hprof 9018
三、内存泄漏分析
1、查看大对象,并梳理调用关系(VisualVM、JProfile、MAT)
2、查看
崩溃前垃圾回收的时间越来越长
四、性能调优
1、线程池:
2、连接池:程序逻辑算法优化(95%的场景通过此方法解决)
3、JVM启动参数:调整各代内存比率和垃圾回收算法、提高吞吐
a、GC时间足够小
b、GC次数足够少
c、FullGC频率足够低
a和b有一定冲突,一般为避免最大最小之间收缩产品额外gc,最大最小设置相同,yong与old比率1:2,NewRadio调整比率,为防止年轻代堆收缩,-XX:newSize -XX:MaxNewSize一样大小,
更大年轻代,更小老年代,大的年轻代会延长普通GC周期,但会增加每次GC的时间;小的年老代会导致更频繁的FullGC;
更小的年轻,更大老年代,小的年轻代会导致普通GC频繁,每次GC时间短,大的年老代减少FullGC频率;
如何选择应该依赖应用程序对象生命周期的分布情况:如果应用存在大量的临时对象,应该选择更大的年轻代;如果存在相对较多的持久对象,年老代应该适当增大。但很多应用都没有这样明显的特性,在抉择时应该根据以下两点:(A)本着Full GC尽量少的原则,让年老代尽量缓存常用对象,JVM的默认比例1:2也是这个道理 (B)通过观察应用一段时间,看其他在峰值时年老代会占多少内存,在不影响Full GC的前提下,根据实际情况加大年轻代,比如可以把比例控制在1:1。但应该给年老代至少预留1/3的增长空间
在配置较好的机器上(比如多核、大内存),可以为年老代选择并行收集算法: -XX:+UseParallelOldGC ,默认为Serial收集
线程堆栈的设置:每个线程默认会开启1M的堆栈,用于存放栈帧、调用参数、局部变量等,对大多数应用而言这个默认值太了,一般256K就足用。理论上,在内存不变的情况下,减少每个线程的堆栈,可以产生更多的线程,但这实际上还受限于操作系统
可以通过下面的参数打Heap Dump信息
- -XX:HeapDumpPath
- -XX:+PrintGCDetails
- -XX:+PrintGCTimeStamps
- -Xloggc:/usr/aaa/dump/heap_trace.txt
请看一下一个时间的Java参数配置:(服务器:Linux 64Bit,8Core×16G)
JAVA_OPTS="$JAVA_OPTS -server -Xms3G -Xmx3G -Xss256k -XX:PermSize=128m -XX:MaxPermSize=128m -XX:+UseParallelOldGC -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/usr/aaa/dump -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:/usr/aaa/dump/heap_trace.txt -XX:NewSize=1G -XX:MaxNewSize=1G"
经过观察该配置非常稳定,每次普通GC的时间在10ms左右,Full GC基本不发生,或隔很长很长的时间才发生一次
通过分析dump文件可以发现,每个1小时都会发生一次Full GC,经过多方求证,只要在JVM中开启了JMX服务,JMX将会1小时执行一次Full GC以清除引用,关于这点请参考附件文档
4、程序算法:程序逻辑算法优化
参考资料:
JVM性能调优之生成堆的dump文件_iTry的博客-CSDN博客_堆dump