学习使用JDK自带工具Java VisualVM(jvisualvm) 分析一次堆内存溢出异常

使用工具

IDEA
JDK8

创建一个java类:

public class HeapOOP {

    static class OOMObject {
        private String name = "abc";
    }

    public static void main(String[] args) {
        List list = new ArrayList();
        try {
            while (true) {
                list.add(new OOMObject());
            }
        } catch (OutOfMemoryError error) {
            System.out.println("list的总大小为:"+list.size());
            throw error;
        }

    }
}

然后修改IDEA的JVM启动参数:
学习使用JDK自带工具Java VisualVM(jvisualvm) 分析一次堆内存溢出异常_第1张图片
接下来:
学习使用JDK自带工具Java VisualVM(jvisualvm) 分析一次堆内存溢出异常_第2张图片
VM options参数值如下:

-verbose:gc
-Xms10M
-Xmx10M
-Xmn5M
-XX:+HeapDumpOnOutOfMemoryError
-XX:+PrintGCDetails
-XX:SurvivorRatio=8

参数说明一下:
-verbose:gc,辅助输出一些详细的gc信息
-Xms:堆初始大小
-Xmx:堆最大值
-Xmn:新生代大小
-XX:+HeapDumpOnOutOfMemoryError: 当有内存溢出错误时自动生成dump文件(文件夹后缀名:.hprof)
-XX:HeapDumpPath:上一个参数生成的文件的路劲
-XX:+PrintGCDetails:输出gc的详细信息
设置好之后,启动该类,正常输出错误信息:

[GC (Allocation Failure) [PSYoungGen: 4597K->512K(4608K)] 6217K->4885K(9728K), 0.0064288 secs] [Times: user=0.00 sys=0.02, real=0.01 secs] 
[Full GC (Ergonomics) [PSYoungGen: 512K->0K(4608K)] [ParOldGen: 4373K->4827K(5120K)] 4885K->4827K(9728K), [Metaspace: 3467K->3467K(1056768K)], 0.0581342 secs] [Times: user=0.05 sys=0.00, real=0.06 secs] 
[Full GC (Ergonomics) [PSYoungGen: 3868K->3295K(4608K)] [ParOldGen: 4827K->4400K(5120K)] 8695K->7695K(9728K), [Metaspace: 3467K->3467K(1056768K)], 0.0682246 secs] [Times: user=0.13 sys=0.00, real=0.07 secs] 
[Full GC (Allocation Failure) [PSYoungGen: 3295K->3295K(4608K)] [ParOldGen: 4400K->4382K(5120K)] 7695K->7677K(9728K), [Metaspace: 3467K->3467K(1056768K)], 0.0506270 secs] [Times: user=0.06 sys=0.00, real=0.05 secs] 
java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid7932.hprof ...
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at java.util.Arrays.copyOf(Arrays.java:3210)
	at java.util.Arrays.copyOf(Arrays.java:3181)
	at java.util.ArrayList.grow(ArrayList.java:265)
	at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:239)
	at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:231)
	at java.util.ArrayList.add(ArrayList.java:462)
	at com.myc.jvm.HeapOOP.main(HeapOOP.java:21)
Heap dump file created [16356051 bytes in 0.051 secs]
list的总大小为:360145
Heap
 PSYoungGen      total 4608K, used 3538K [0x00000000ffb00000, 0x0000000100000000, 0x0000000100000000)
  eden space 4096K, 86% used [0x00000000ffb00000,0x00000000ffe74bd0,0x00000000fff00000)
  from space 512K, 0% used [0x00000000fff80000,0x00000000fff80000,0x0000000100000000)
  to   space 512K, 0% used [0x00000000fff00000,0x00000000fff00000,0x00000000fff80000)
 ParOldGen       total 5120K, used 4382K [0x00000000ff600000, 0x00000000ffb00000, 0x00000000ffb00000)
  object space 5120K, 85% used [0x00000000ff600000,0x00000000ffa479d8,0x00000000ffb00000)
 Metaspace       used 3499K, capacity 4500K, committed 4864K, reserved 1056768K
  class space    used 382K, capacity 388K, committed 512K, reserved 1048576K

Process finished with exit code 1

接下来,寻找生成的错误的dump文件,如果没指定-XX:HeapDumpPath,那么该dump文件在项目跟目录下,根据进程号命名了。

找到JDK的bin目录下有一个文件:jvisualvm.exe,双击打开:
学习使用JDK自带工具Java VisualVM(jvisualvm) 分析一次堆内存溢出异常_第3张图片
选择:文件->装入,找到自己的dump文件:
学习使用JDK自带工具Java VisualVM(jvisualvm) 分析一次堆内存溢出异常_第4张图片
然后打开,就可以在首页看到概要信息,在概要信息能够看到导致这次异常的线程信息:
学习使用JDK自带工具Java VisualVM(jvisualvm) 分析一次堆内存溢出异常_第5张图片
点击线程名,跳转到详细信息:
学习使用JDK自带工具Java VisualVM(jvisualvm) 分析一次堆内存溢出异常_第6张图片
咱们查看源码,可以看到,在往List中添加对象的地方导致了错误。
再点到“类”页面,看一下信息:
学习使用JDK自带工具Java VisualVM(jvisualvm) 分析一次堆内存溢出异常_第7张图片
发现类

OOMObject

的实例数已经达到了360146个,这么多的实例,导致堆内存已经不够用,且没有被GC给回收(具体为啥没回收,暂且不讨论,跟上面设置的JVM参数有关,这个后续再慢慢记录)。所以JVM就报出了内存溢出错误。
学习Java VisualVM的一次记录。
本次学习的的相关资料:
《深入理解Java虚拟机》周志明著
JVM虚拟机的一些参数设置
JVM参数-XX:+HeapDumpOnOutOfMemoryError使用方法

你可能感兴趣的:(java)