堆内存溢出:
堆内存溢出:java堆内存不够,一个原因是真不够,另一个原因是程序中有死循环;
下面演示的是利用循环的方式在堆中持续建立对象,直到堆内存满溢。
代码:
public class HeapOOM {
public static void main(String[] args) {
/**
* maxMemory()为JVM的最大可用内存,可通过-Xmx设置,默认值为物理内存的1/4,设值不能高于计算机物理内存;
*/
System.out.println("最大可用内存,对应-Xmx(默认物理内存的4分之1):"+
Runtime.getRuntime().maxMemory()/(1024*1024));
/**
* totalMemory()为当前JVM占用的内存总数,其值相当于当前JVM已使用的内存及freeMemory()的总和,
* 会随着JVM使用内存的增加而增加;
*/
System.out.println("当前JVM可用空间:"+
Runtime.getRuntime().freeMemory()/(1024*1024));
/**
* freeMemory()为当前JVM空闲内存,因为JVM只有在需要内存时才占用物理内存使用,
* 所以freeMemory()的值一般情况下都很小,而 JVM实际可用内存并不等于freeMemory(),
* 而应该等于maxMemory()-totalMemory()+freeMemory()。及其 设置JVM内存分配。
*/
System.out.println("当前JVM占用的内存总数,相当于已使用的内存加上空闲空间:"+
Runtime.getRuntime().totalMemory()/(1024*1024));
List<OOMObject> list = new ArrayList<>();
while (true){
list.add(new OOMObject());
System.out.println("最大可用内存,对应-Xmx(默认物理内存的4分之1):"+
Runtime.getRuntime().maxMemory()/(1024*1024));
System.out.println("当前JVM可用空间:"+
Runtime.getRuntime().freeMemory()/(1024*1024));
System.out.println("当前JVM占用的内存总数,相当于已使用的内存加上空闲空间:"+
Runtime.getRuntime().totalMemory()/(1024*1024));
}
}
}
修改调试时的虚拟机参数:
-Xms:初始堆大小
-Xmx:最大堆大小
-XX:+HeapDumpOnOutOfMemoryError :生成堆转储文件
运行main方法,显示结果:
...
最大可用内存,对应-Xmx(默认物理内存的4分之1):5
当前JVM可用空间:0
当前JVM占用的内存总数,相当于已使用的内存加上空闲空间:5
最大可用内存,对应-Xmx(默认物理内存的4分之1):5
当前JVM可用空间:0
当前JVM占用的内存总数,相当于已使用的内存加上空闲空间:5
java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid12572.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:261)
at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:235)
at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:227)
at java.util.ArrayList.add(ArrayList.java:458)
at com.example.outofmemoryerror.HeapOOM.main(HeapOOM.java:40)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
Heap dump file created [10636779 bytes in 0.052 secs]
利用MemoryAnalyzer打开堆转储文件java_pid12572.hprof可以看到
空间剩余只有302.2KB
然后查看具体内存消耗情况:
可以看到内存主要消耗在main主线程中,而main主线程中又主要是java.lang.Object对象占用的空间太大,也就是OOMObject对象太多,创建了160065个OOMObject对象,占用了太大的空间。