有没有处理过内存泄漏问题?是如何定位的?

有没有处理过内存泄漏问题?是如何定位的?
内存泄漏是一种内在病源,其外在症状可能包括:
- 长时间连续运行的应用程序性能严重下降。
- CPU使用率飙升,甚至达到100%。
- 频繁的Full GC,以及各种报警,如接口超时报警等。
- 应用程序抛出OutOfMemoryError错误。
- 应用程序偶尔耗尽连接对象。
严重的内存泄漏通常会伴随频繁的Full GC,因此在分析和排查内存泄漏问题时,首先需要查看Full GC情况。以下是主要的操作步骤:
1)使用jps
命令查看正在运行的Java进程ID。
2)使用top -p [pid]
命令查看进程的CPU和内存使用情况。
3)使用top -Hp [pid]
命令查看进程下所有线程的CPU和内存情况。
4)将线程ID转换为16进制:printf "%x\n" [pid]
,输出的值即为线程栈信息中的nid。
例如:printf "%x\n" 29471
,输出为731f。
5)抓取线程栈:jstack 29452 > 29452.txt
,可以多次抓取以进行比较。
在线程栈信息中查找对应线程号的16进制值,以下是线程信息示例。可以使用VisualVM插件TDA进行线程栈分析。
"Service Thread" #7 daemon prio=9 os_prio=0 tid=0x00007fbe2c164000 nid=0x731f runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
6)使用jstat -gcutil [pid] 5000 10
命令每隔5秒输出GC信息,输出10次,查看YGC和Full GC的次数。通常情况下,YGC要么不增加,要么增加缓慢,而Full GC会迅速增加。
或者使用jstat -gccause [pid] 5000
命令输出GC摘要信息。
或者使用jmap -heap [pid]
命令查看堆的摘要信息,关注老年代内存使用是否达到阈值,如果达到阈值,就会执行Full GC。
7)如果发现Full GC的次数过多,很有可能存在内存泄漏。
8)使用jmap -histo:live [pid]
命令输出每个类的对象数量、内存大小(以字节为单位)和完整类名。
9)生成dump文件,并借助工具分析具有大量对象的位置。
使用jmap生成dump文件的示例:
# jmap -dump:live,format=b,file=29471.dump 29471
Dumping heap to /root/dump ...
Heap dump file created
10)对dump文件进行
分析。
可以使用jhat命令进行分析:jhat -port 8000 29471.dump
,然后在浏览器中访问jhat服务,端口为8000。
通常可以使用图形化工具进行分析,如JDK自带的jvisualvm,从菜单中选择文件 -> 载入dump文件。
也可以使用第三方工具进行分析,如JProfiler和GCViewer。Eclipse IDE也提供了MAT工具进行分析,还可以使用在线分析平台GCEasy。
请注意,如果dump文件较大,则分析过程可能会占用较大内存。
11)在dump文件分析结果中查找存在大量对象的位置,并查看对这些对象的引用。
通过以上步骤,基本上可以定位到代码层面的逻辑问题。