在实际的开发过程中,我们经常遇到
java.lang.OutOfMemoryError
异常,那么如何定位是程序的哪里出现这个异常的呢?本博文将体验OutOfMemoryError的定位
本博文体验的软件环境
JDK版本 | IDE |
---|---|
Java 1.8.0.144_x64 | IDEA 2019.1 |
- 编写OutOfMemoryError的代码
public class Test {
public static void main(String[] args) {
List<E> list = new ArrayList<>();
// 不断的循环添加对象
while (true) {
list.add(new E());
}
}
}
class E {
}
-
我们打开IDEA中的VM Arguements参数的设置
image
然后我们在上面 VM options中输入-XX:+HeadDumpOnOutOfMemoryError -Xms20m -Xmx20m
,下面的Working directory是生成的堆内存快照的目录路径
上述参数的意义:
- -XX:+HeapDumpOnOutOfMemoryError
生成堆内存的快照
- -Xms20m
为jvm启动时分配的内存,比如-Xms20m,表示分配20M
- -Xmx20m
设置JVM最大可用内存为20M
-Xms和-Xmx设置一样的,避免每次垃圾回收完成后JVM重新分配内存
- 运行该程序
我们很快就能发现,程序报java.lang.OutOfMemoryError: Java heap space
异常,在对应的目录环境下,我们可以发现生成了 堆内存快照,每次运行都生成当前运行进程号pid对应的内存版本快照,可以根据进程号获取对应的内存版本快照
这是一个hprof类型的文件,我们打开也是乱码,那么我们怎么查看呢?
- 安装JProfiler内存分析工具
安装结束之后,如下图
image注意,这里安装的插件只是将JProfiler的入口集成到IDEA中,我们还需要下载JProfiler软件安装到需要本机的环境中
下载的地址:
JProfiler
安装完成之后,我们来修改下我们的程序
public class Test {
public static void main(String[] args) {
List<E> list = new ArrayList<>();
while (true) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
list.add(new E());
}
}
}
class E {
// 让对象有一定大小
public byte[] bytes = new byte[10 * 1024];
}
程序中的睡眠主要是为了让程序不会一下子结束,我们就可以点击上面的jProfiler按钮,进入界面观察具体的内存情况
- 执行程序,点击JProfiler按钮(上面截图的按钮)进行如下的操作:
显示当前程序执行的内存、CPU和GC的情况
image从图中我们其实已经看到程序已经发生了GC了
点击【Memory】查看内存使用情况
image从图中我们可以看到我们设置的最大可用的内存情况,并且当前看到当前随着程序运行,当使用的内存不断增大,达到最大的可用内存时,程序就会OutOfMemoryError,我们也可以通过选择不同的【Memory Pool】来查看不同区域的内存情况
- 我们也可以软件来查看hprof类型的文件
之前我们配置过VM Options的参数,输入的内存快照,如果我们想看看内存快照具体是显示什么内容,我们可以通过 【Memory Analyzer】这个软件来查看
这个是本地运行来查看dump日志的软件
image如果我们想要查看具体的程序执行情况,想要查看是哪些代码造成内存溢出的,我们可以进行如下操作
image从上图中我们可以看到造成内存异常的主要是om.amos.tools.common.E
对象的大量创建
综上就是我们跟踪正常执行的和内存快照查看的具体操作,以后我们在整理JVM分析时可以用来跟踪程序执行情况以及发生GC的主要原因
网友评论