故事背景
cpu持续走高,直接导致服务器宕机,无法对外提供服务。
排查思路
1. 一般cpu过高只有两种情况:1.线程太多,可以用命令看一下;2.频繁full gc,因为full gc是很消耗cpu资源的。
2. 用jstat命令看了下,果然是频繁full gc造成的。但是内存分配比例和大小还是很合理的。新生代10g,老年代10g,可是每次ygc后都有1g左右对象去到老年代
3. 基于上述情况、那这时候调整内存比例也不会有任何意义了,猜想是内存泄露引起的。因为老年代停留了大量对象无法回收,每次稍微ygc过来一点对象就会引起fgc
于是就生成内存快照进行分析下 jmap -dump:format=b,file=demo.hprof PID
内存泄漏
1. 下载mat工具 https://www.eclipse.org/mat/downloads.php
2. 直接打开MemoryAnalyzer.exe就好了。(MemoryAnalyzer.ini文件默认限制了-Xmx1024m,一般生产环境导出的demp很大的,可以把这个调大一点)
3. file -> open heap dump -> 选择刚才的快照文件就好了
4. Problem Suspect 1 已经说的很清楚了 java.lang.Thread @ 0xe3805d30 main 线程的java.lang.Object[]占用了53.85%内存对象。
点击 Details 可以看到 Accumulated Objects in Dominator Tree 的main线程中引用了一个 java.util.ArrayList ,他是一个java.lang.Object[]数组,里面全是demo1对象
点击 See stacktrace 就能看到线程执行代码堆栈的调用链
说白了,就是一次性加载过多数据到内存里来导致的,可以考虑数据分批处理或者多个线程并发执行。
什么是内存泄漏及如何避免
内存泄漏即:对象可达但不可用,程序不需要用某个对象,但另一个正在使用的对象却持有它的引用,导致无法回收停留在堆内中。
防止内存泄露:
1.尽早释放无用对象的引用, 将不需要使用的对象设置为null,暗示垃圾收集器来收集该对象,防止发生内存泄漏。
2.程序进行字符串处理时,尽量避免使用String,而应该使用StringBuffer。
3.尽量少用静态变量
4.尽量运用对象池技术以提高系统性能