05_内存溢出_分析
什么是堆Dump
堆Dump是反应Java堆使用情况的内存镜像,其中主要包括系统信息、虚拟机属性、完整的线程Dump、所有类和对象的状态等。 一般,在内存不足、GC异常等情况下,我们就会怀疑有内存泄露。这个时候我们就可以制作堆Dump来查看具体情况。
当我们在做压测的时候,如果遇到服务器返回
outOfMemoryError 年老代内存不足。
outOfMemoryError:PermGen Space 永久代内存不足。
outOfMemoryError:GC overhead limit exceed 垃圾回收时间占用系统运行时间的98%或以上
这说明你的jvm中堆的内存不足,GC无法进行回收
这个时候我们就需要去分析因为是因为说明原因造成的!
注:当有内存溢出,程序无法访问的时候,不要赶紧去重启服务器,首先我们可以把堆中的信息dump下来
这里介绍一下jmap这个命令:
jmap -dump:将内存使用的详细情况输出到文件
- 这个命令执行,JVM会将整个heap的信息dump写入到一个文件,heap如果比较大的话,就会导致这个过程比较耗时,并且执行的过程中为了保证dump的信息是可靠的,所以会暂停应用。

linux中输入jmap查看帮助文档,关于jmap -dump给了详细的example,我们只需要拷贝一下,然后把pid改成tomcat启动的进程号就行
例:
先查看启动的tomcat进程号:ps -ef|grep tomcat

执行:jmap -dump:live,format=b,file=heap.bin 1163

会在当前的目录下面生成一个heap.bin文件,这样就把堆中的信息dump下来,然后可以利用eclipse的mat插件进行分析
mat下载地址
提取码:6j78



然后file--open file 找的从linux中下载到本地的heap.bin文件(具体的使用方法就不教了,网上可自行看一下)
也可以使用 jhat 打开刚刚dump下来的文件,主要是用来分析java堆的命令,可以将堆中的对象以html的形式显示出来,包括对象的数量,大小等等,并支持对象查询语言。:
执行:jhat heap.bin
启动一个http服务,端口要是7000,在浏览器中输入本机的ip,加上端口号7000
Started HTTP server on port 7000


jhat详细介绍:https://www.cnblogs.com/baihuitestsoftware/articles/6406271.html
通过命令查看大对象
jmap -histo <pid>|less
进入命令要退出: q
- 可得到如下包含对象序号、某个对象示例数、当前对象所占内存的大小、当前对象的全限定名,
如下图:

查看对象数最多的对象,并按降序排序输出:
执行:jmap -histo <pid>|grep tomcat|sort -k 2 -g -r|less

查看占用内存最多的最象,并按降序排序输出:
执行:jmap -histo <pid>|grep tomcat|sort -k 3 -g -r|less
结果如图

友情提示:jmap -histo:live pid>a.log,可以先将命令结果重定向到一个文件中,在一段时间后,使用文本对比工具,可以对比出GC回收了哪些对象!
#instance 是对象的实例个数
#bytes 是总占用的字节数
class name 对应的就是 Class 文件里的 class 的标识
B 代表 byte
C 代表 char
D 代表 double
F 代表 float
I 代表 int
J 代表 long
Z 代表 boolean
前边有 [ 代表数组, [I 就相当于 int[]
对象用 [L+ 类名表示
jstat -gcutil 实时查看堆运行情况
命令:jstat -gcutil 1163 2000 10
jstat -gcutil pid 多久展现一次 展现多少次

S0:第一个幸存区的使用大小
S1:第二个幸存区的使用大小
E:伊甸园区的使用大小
O:老年代使用大小
M:方法区使用大小
CCS:压缩类空间使用大小
YGC:年轻代垃圾回收次数
YGCT:年轻代垃圾回收消耗时间
FGC:老年代垃圾回收次数
FGCT:老年代垃圾回收消耗时间
GCT:垃圾回收消耗总时间
当FGC一直在增加,O达到了95%或者100%的时候,由于内存不住,会执行fullGC回收内存,但是由于老年区的内存被占用无法进行回收,两者冲突就会不断的执行FGC,增加FQC的次数!这个时候你就需要去排查
性能问题查找
1、发现问题
1)、使用uptime命令查看CPU的Load情况,Load越高说明问题越严重;
2)、使用jstat查看FGC发生的频率及FGC所花费的时间,FGC发生的频率越快、花费的时间越高,问题越严重;
总结
1.如果程序内存不足或者频繁GC,很有可能存在内存泄露情况,这时候就要借助Java堆Dump查看对象的情况。
2.要制作堆Dump可以直接使用jvm自带的jmap命令
3.可以先使用jmap -heap命令查看堆的使用情况,看一下各个堆空间的占用情况。
4.使用jmap -histo:[live]查看堆内存中的对象的情况。如果有大量对象在持续被引用,并没有被释放掉,那就产生了内存泄露,就要结合代码,把不用的对象释放掉。
5.也可以使用 jmap -dump:format=b,file=<fileName>命令将堆信息保存到一个文件中,再借助jhat命令查看详细内容
6.在内存出现泄露、溢出或者其它前提条件下,建议多dump几次内存,把内存文件进行编号归档,便于后续内存整理分析。
7.在用cms gc的情况下,执行jmap -heap有些时候会导致进程变T,因此强烈建议别执行这个命令,如果想获取内存目前每个区域的使用状况,可通过jstat -gc或jstat -gccapacity来拿到。