调优背景:
项目运行卡顿,页面加载慢。
排查问题思路:
查看CPU使用率,内存使用率,分析是否有耗时的线程,是否由于编码不规范导致产生对象过多等。
使用’top’命令,查看cpu使用率(%CPU),内存使用率(%MEM),PID进程ID
使用’top -Hp pid’命令,查看进程中线程耗费CPU的时间
使用’printf “%x\n” 线程id’命令,得到线程id的十六进制值
使用’jstack 进程id | grep 线程id的十六进制值’命令查看进程的堆栈信息
可以看到,是垃圾回收线程cpu使用率较高,说明一直在进行垃圾回收
使用’jmap -heap pid’再来看一下堆内存的具体使用情况
老年代基本被占满,所以导致了频繁FGC。但是未发生内存溢出错误,猜测是项目本身需要初始化对象占用的空间较大。
使用’jmap -histo:live pid | more’命令,查看内存中的存活对象情况
可以看到字节数组占用空间最大(约113MB)
猜测是下面的map中存放了很多String和字节数组,需要熟悉项目架构再具体分析。
使用’jmap -dump:format=b,file=/目录/文件名.dat pid’命令导出dump文件。
使用jvisualvm(jdk的bin目录下)作进一步分析。(若dump文件过大,不建议生成dump文件,导出过程会影响程序运行)
从上至下是对象占用空间的排序,
需要进一步熟悉业务代码,哪里有使用了较多的字节数组,字符串,集合
发现有循环引用,可能是导致无法被垃圾回收器回收掉的原因?
使用’jstat -gc pid 采样时间间隔 采样数量’命令,查看垃圾回收信息
可以看到平均不到2s就要触发一次FULL GC,并且每次GC后,堆的已使用空间并未明显减少,说明存货对象较多,同时,也未见有明显增长,说明是项目本身运行需要初始化约456.8MB的对象空间
调整堆空间内存为2GB后,再次查看垃圾回收信息
如图,间隔60s采样,采样十次
总结:
老年代空间使用增长依然略快,建议按照上面分析优化代码。
堆空间内存调整为2G后,基本可以平稳运行,建议线上调整为4G左右。或调整年轻代和老年代比率,提升年轻代空间,减少YGC。