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启动参数:
接下来:
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,双击打开:
选择:文件->装入,找到自己的dump文件:
然后打开,就可以在首页看到概要信息,在概要信息能够看到导致这次异常的线程信息:
点击线程名,跳转到详细信息:
咱们查看源码,可以看到,在往List中添加对象的地方导致了错误。
再点到“类”页面,看一下信息:
发现类
OOMObject
的实例数已经达到了360146个,这么多的实例,导致堆内存已经不够用,且没有被GC给回收(具体为啥没回收,暂且不讨论,跟上面设置的JVM参数有关,这个后续再慢慢记录)。所以JVM就报出了内存溢出错误。
学习Java VisualVM的一次记录。
本次学习的的相关资料:
《深入理解Java虚拟机》周志明著
JVM虚拟机的一些参数设置
JVM参数-XX:+HeapDumpOnOutOfMemoryError使用方法