Java的dump文件分析及JProfiler使用
1 dump文件介绍
从软件开发的角度上,dump文件就是当程序产生异常时,用来记录当时的程序状态信息(例如堆栈的状态),用于程序开发定位问题。
idea配置发生OOM的时候指定路径生成dump文件
# 指定发生OOM异常的时候,在d盘下生成对应的dump文件
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=d:\
 
2 JProfiler介绍
2.1 下载
JProfiler下载:
链接:https://pan.baidu.com/s/1WXCc4FMOC3QQtjkhY4Qeow
提取码:5xrm
版本:JProfiler 12.0.4
2.2 与idea集成
-  
本地windows下载并安装好JProfiler
 -  
idea安装JProfiler插件

 -  
指定本地windows的JProfiler路径[settings - tools]
 

 4. 点击图标启动,JProfiler就默认监控到了指定Java程序
 
2.3 基本使用
①JProfiler基本参数
②测试分析dump文件
- 模拟OOM
 
public class JProfilerTest {
    public static void main(String[] args) throws InterruptedException {
        List<byte[]> list = new ArrayList<>();
        while (true) {
            byte[] bytes = new byte[1024 * 1024 * 50];
            list.add(bytes);
            TimeUnit.SECONDS.sleep(1);
        }
    }
}
 
- 程序添加VM Options
 
# 监控OOM,发生OOM之后指定dump文件生成到d:\
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=d:\
 

- JProfiler方式启动程序,观察控制台打印
 
程序运行一段时间之后,发生OOM异常
 
 5. 查看dump文件,用JProfiler打开
 
 6. 分析dump文件
 
查看最大对象内部结构

可以发现是改list中含有了太多的byte[]数组
ps:其他查看方法类似
3 常见JVM问题
3.1 OOM
①堆溢出
原因:
1. 无法在Java堆中分配对象
2. 应用程序保存了无法被GC回收的对象
3. 程序过度使用finalizer
 
排查思路:
- 查看关键报错信息
 - 使用内存映像分析工具(MAT或JProfiler)分析dump文件,分析是内存泄漏还是内存溢出
 - 如果是内存泄漏,通过工具查看泄漏对象到GC Roots引用链,修复内存泄漏
 - 如果不是,检查代码是否有死循环,递归等,再考虑用
 -Xmx增加堆大小
demo代码JVM配置参数:
- -Xms20m JVM初始分配的内存20m
 - -Xmx20m JVM最大可用内存为20m
 - -XX:+HeapDumpOnOutOfMemoryError 当JVM发生OOM时,自动生成DUMP文件
 - -XX:HeapDumpPath=/Users/mytest/Desktop/dump/ 生成DUMP文件的路径
 
②栈溢出
栈:虚拟机栈和本地方法栈,关于栈,Java虚拟机规范中描述了两种异常:
StackOverflowError:线程请求的栈深度大于虚拟机所允许的深度OOM:如果虚拟机栈可以动态扩展,当扩展时无法申请到足够的内存时会抛出
原因:
1. 单个线程下,栈帧太大或虚拟机栈容量太小,内存无法分配
2. 不断建立线程
 
排查思路:
- 查看关键报错信息,确定是StackOverflow还是OOM
 - 如果是StackOverflow,检查代码是否存在递归
 - 如果是OOM,检查是否有死循环创建线程或调用第三方接口创建线程,通过
 -Xss降低每个线程栈大小
③方法区溢出
方法区(又叫永久代,JDK8之后元空间替换了永久代),用于存放Class的相关信息,如:类名、访问修饰符、常量池、字段描述、方法描述等。运行时产生大量的类,会填满方法区,造成溢出。
溢出原因:
1. 使用CGLib生成大量代理类
2. 在Jdk7之前,频繁错误的使用String.intern方法
3. 大量jsp和动态产生jsp
4. 应用长时间运行,没有重启
 
排查思路:
- 检查是否永久代空间设置的过小
 
-XX:MetaspaceSize=10M -XX:MaxMetaspaceSize=10M- 是否频繁错误使用String.intern
 - 是否与jsp有关
 - 是否使用CGLib生成大量代理类
 - 重启JVM
 
④直接内存溢出
直接内存不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域。但是,这部分也被频繁的使用,也可能导致OOM。
原因:
1. 本机直接内存不受到Java堆大小限制,但是受到本机总内存大小限制
2. 直接内存由-XX:MaxDirectMemorySize指定,如果不指定,默认与Java堆最大值
	一样(-Xmx)
3. NIO程序中,使用ByteBuffer.allocateDirect(capability)分配的是直接内
	存,可能导致直接内存溢出
 
排查思路:
- 检查代码是否恰当
 - 检查JVM参数
 -Xmx(java堆最大值),-XX:MaxDirectMemorySize是否合理
参考:https://zhuanlan.zhihu.com/p/95150243


















