一、堆区和非堆区
前言:
如果发生内存溢出,主要是通过内存映像文件,来查看到底是那些类,一直在占有没有释放。
- 1.1 情况分析:
第一种内存溢出:有可能内存泄漏
第二种内存溢出:也有可能内存分配不足导致的
假若:内存泄漏,我们要找到是那个地方把它泄露出去了,一直占有没有释放。
java中的内存泄漏:指new了一个对象之后,一直不释放,这样的内存
- 1.2 如何导出内存映像文件?
- 1.2.1 内存溢出JVM自动导出:
当发生内存溢出的时候让jvm自动导出
设置参数:
#当发生内存溢出的时候,把HeapDump导出
-XX:+HeapDumpOnOutOfMemoryError
#当发生内存溢出的时候,把HeapDump出来的路径
-XX:HeapDumpPath=./
- 1.2.2 使用jmap命令手动导出:
当发生内存溢出的时候,再去dump就有点晚了,当成程序运行一点时间后,我们用jmap手动导出内存映像文件,来具体分析:
执行命令:
jmap -dump:format=b,file=heap.hprof 3456
格式:jmap -dump:format=b,file=heap.hprof pid
命令行输出:
Dumping heap to C:\Users\Administrator.PC-20180929LWLP\Desktop\heap.hprof ...
Heap dump file created
看到以上提示,说明导出成功!!!
二、MAT分析dump文件
打开dump文件
三、案例演示
框架springboot
在浏览器地址栏输入:https://start.spring.io/
- 3.1 生成一个springboot项目
- 3.2 解压压缩包
- 3.3 在STS或eclipse或idea导入解压的项目
- 3.4创建一个MemoryController和User对象
实现原理:
因为controller不被回收,它里面的成员变量也 是不会被被回收的,这样就是导致list里面的对象越来越多,占得内存会越来越大,这样就会把我们这个内存撑爆了。
构造内存溢出
1.定义一个 list
2.通过一个循环不停地往这个list里面添加对象
3.5 启动项目,添加参数
浏览器验证:
http://localhost:8080/heap
控制台输出:
Exception in thread “http-nio-12345-exec-3” java.lang.OutOfMemoryError: GC overhead limit exceeded
模拟内存溢出自动导出:
-Xmx32M -Xms32M -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./
注:./指项目根目录
控制台输出:
java.lang.OutOfMemoryError: GC overhead limit exceeded
Dumping heap to ./\java_pid12468.hprof …
Heap dump file created [44843683 bytes in 0.270 secs]
mat分析dump文件:
mat下载地址:
https://www.eclipse.org/mat/downloads.php
双击打开
很明显在MemoryController中,有一个userList,在userList中User对象很多都没有释放。
CPU 线程 线程分析:
结果已经很明显了,解决方案就是:释放对象User就可以了
模拟使用jmap命令手动导出:
总结:理论上说:这2中都可以用,当内存很大的时候自动导出会导不出来,建议使用jmap手动导出即可
jmap -heap 3456
可以看到那一块具体用了多少
上面是导出内存映像文件,下面来用MAT
分析内存溢出,内存映像文件到底存了什么东西?如何利用内存映像文件来定位内存溢出呢?
https://www.eclipse.org/downloads/download.php
jstack pid > pid.txt
sz pid.txt
线程状态
top -p 15764 -H
https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot
https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/tooldescr034.html
多么痛的领悟-代码优化导致的BUG
blog.csdn.net/goldenfish1919/article/details/8755378
nohup java -jar monitor_tuuning-0.0.1-SNAPSHOT.jar &
10.5.6.142:12345/loop
top命令查看cpu负载,load acerage:
cpu负载变大请求就进不来了
解决方案:
jstack pid > pid pid.txt
sz pid.txt :下载命令
top -p pid -H:打印所有线程,筛选出占用cpu比较多的线程,看看占用cpu线程在干什么?
printf “%x” pid :线程pid
命令行pid是十进制的,导出的jstack 文件时十六进制的
10.5.6.142/deadlock
CATALINA_OPTS="$CATALINA_OPTS -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=8888 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -Djava.rmi.server.hostname=10.5.6.120"
JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=8888 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -Djava.rmi.server.hostname=10.5.6.120"
nohup java -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=8888 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -Djava.rmi.server.hostname=10.5.6.120 -jar monitor_tuuning-0.0.1-SNAPSHOT.jar &
tail -f nohup.out
jmap手动导出内存映像文件
命令行执行:
jmap -dump:format=b,file=heap.hprof 3456
格式:jmap -dump:format=b,file=heap.hprof pid
[root@localhost ~]# cd /app/nmonlogs/
[root@localhost nmonlogs]# ./nmon
按c查看CPU使用信息,按m查看内存使用信息,按n查看网络使用信息
c
jmap -dump:format=b,file=heap.hprof 31322