堆內(nèi)存溢出:
堆內(nèi)存溢出:java堆內(nèi)存不夠,一個(gè)原因是真不夠,另一個(gè)原因是程序中有死循環(huán);
下面演示的是利用循環(huán)的方式在堆中持續(xù)建立對象,直到堆內(nèi)存滿溢。
代碼:
public class HeapOOM {
public static void main(String[] args) {
/**
* maxMemory()為JVM的最大可用內(nèi)存,可通過-Xmx設(shè)置,默認(rèn)值為物理內(nèi)存的1/4,設(shè)值不能高于計(jì)算機(jī)物理內(nèi)存;
*/
System.out.println("最大可用內(nèi)存,對應(yīng)-Xmx(默認(rèn)物理內(nèi)存的4分之1):"+
Runtime.getRuntime().maxMemory()/(1024*1024));
/**
* totalMemory()為當(dāng)前JVM占用的內(nèi)存總數(shù),其值相當(dāng)于當(dāng)前JVM已使用的內(nèi)存及freeMemory()的總和,
* 會隨著JVM使用內(nèi)存的增加而增加;
*/
System.out.println("當(dāng)前JVM可用空間:"+
Runtime.getRuntime().freeMemory()/(1024*1024));
/**
* freeMemory()為當(dāng)前JVM空閑內(nèi)存,因?yàn)镴VM只有在需要內(nèi)存時(shí)才占用物理內(nèi)存使用,
* 所以freeMemory()的值一般情況下都很小,而 JVM實(shí)際可用內(nèi)存并不等于freeMemory(),
* 而應(yīng)該等于maxMemory()-totalMemory()+freeMemory()。及其 設(shè)置JVM內(nèi)存分配。
*/
System.out.println("當(dāng)前JVM占用的內(nèi)存總數(shù),相當(dāng)于已使用的內(nèi)存加上空閑空間:"+
Runtime.getRuntime().totalMemory()/(1024*1024));
List<OOMObject> list = new ArrayList<>();
while (true){
list.add(new OOMObject());
System.out.println("最大可用內(nèi)存,對應(yīng)-Xmx(默認(rèn)物理內(nèi)存的4分之1):"+
Runtime.getRuntime().maxMemory()/(1024*1024));
System.out.println("當(dāng)前JVM可用空間:"+
Runtime.getRuntime().freeMemory()/(1024*1024));
System.out.println("當(dāng)前JVM占用的內(nèi)存總數(shù),相當(dāng)于已使用的內(nèi)存加上空閑空間:"+
Runtime.getRuntime().totalMemory()/(1024*1024));
}
}
}
修改調(diào)試時(shí)的虛擬機(jī)參數(shù):

image.png
-Xms:初始堆大小
-Xmx:最大堆大小
-XX:+HeapDumpOnOutOfMemoryError :生成堆轉(zhuǎn)儲文件
運(yùn)行main方法,顯示結(jié)果:
...
最大可用內(nèi)存,對應(yīng)-Xmx(默認(rèn)物理內(nèi)存的4分之1):5
當(dāng)前JVM可用空間:0
當(dāng)前JVM占用的內(nèi)存總數(shù),相當(dāng)于已使用的內(nèi)存加上空閑空間:5
最大可用內(nèi)存,對應(yīng)-Xmx(默認(rèn)物理內(nèi)存的4分之1):5
當(dāng)前JVM可用空間:0
當(dāng)前JVM占用的內(nèi)存總數(shù),相當(dāng)于已使用的內(nèi)存加上空閑空間: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打開堆轉(zhuǎn)儲文件java_pid12572.hprof可以看到

image.png
空間剩余只有302.2KB
然后查看具體內(nèi)存消耗情況:

image.png
可以看到內(nèi)存主要消耗在main主線程中,而main主線程中又主要是java.lang.Object對象占用的空間太大,也就是OOMObject對象太多,創(chuàng)建了160065個(gè)OOMObject對象,占用了太大的空間。