經過簡單的小例子程序,演示java虛擬機各部份內存溢出狀況:java
(1).java堆溢出:web
Java堆用於存儲實例對象,只要不斷建立對象,而且保證GC Roots到對象之間有引用的可達,避免垃圾收集器回收實例對象,就會在對象數量達到堆最大容量時產生OutOfMemoryError異常。多線程
想要方便快速地產生堆溢出,要使用以下java虛擬機參數:-Xms10m(最小堆內存爲10MB),-Xmx10m(最大堆內存爲10MB,最小堆內存和最大堆內存相同是爲了不堆動態擴展),-XX:+HeapDumpOnOutOfMemoryError可讓java虛擬機在出現內存溢出時產生當前堆內存快照以便進行異常分析。app
例子代碼以下:ide
運行一段時間就會發現產生OutOfMemoryError異常,而且產生了堆內存異常dump文件。oop
(2).java虛擬機棧和本地方法棧溢出:url
因爲Sun的HotSpot虛擬機不區分java虛擬機棧和本地方法棧,所以對於HotSpot虛擬機來講-Xoss參數(設置本地方法棧大小)雖然存在,可是其實是無效的,棧容量只能由-Xss參數設定。spa
因爲Java虛擬機棧會出現StackOverflowError和OutOfMemoryError兩種異常,因此分別使用兩個例子演示這兩種狀況:操作系統
a.java虛擬機棧深度溢出:.net
單線程的環境下,不管是因爲棧幀太大,仍是虛擬機棧容量過小,當內存沒法再分配的時候,虛擬機總拋出StackOverflowError異常。使用-Xss128k將java虛擬機棧大小設置爲128kb,例子代碼以下:
運行一段時間後,產生StackOverflowError異常。Java虛擬機棧溢出通常會產生在方法遞歸調用過多而java虛擬機棧內存不夠的狀況下。
b.java虛擬機棧內存溢出:
多線程環境下,可以建立的線程最大內存=物理內存-最大堆內存-最大方法區內存,在java虛擬機棧內存必定的狀況下,單個線程佔用的內存越大,所能建立的線程數目越小,因此在多線程條件下很容易產生java虛擬機棧內存溢出的異常。
使用-Xss2m參數設置java虛擬機棧內存大小爲2MB,例子代碼以下:
運行一段時間以後,java虛擬機棧就會由於內存過小沒法建立線程而產生OutOfMemoryError。
(3).運行時常量池溢出:
運行時常量池屬於方法區的一部分,能夠使用-XX:PermSize=10m和-XX:MaxPermSize=10m將永久代最大內存和最小內存設置爲10MB大小,而且因爲永久代最大內存和最小內存大小相同,所以沒法擴展。
String的intern()方法用於檢查常量池中若是有等於此String對象的字符串存在,則直接返回常量池中的字符串對象,不然,將此String對象所包含的字符串添加到運行時常量池中,並返回此String對象的引用。所以String的intern()方法特別適合演示運行時常量池溢出,例子代碼以下:
運行一段時間,永久代內存不夠,運行時常量池因沒法再添加常量而產生OutOfMemoryError。
(4).方法區溢出:
運行時常量池是方法區的一部分,他們都屬於HotSpot虛擬機中的永久代內存區域。方法區用於存放Class的相關信息,Java的反射和動態代理能夠動態產生Class,另外第三方的CGLIB能夠直接操做字節碼,也能夠動態產生Class,實驗經過CGLIB來演示,一樣使用-XX:PermSize=10m和-XX:MaxPermSize=10m將永久代最大內存和最小內存設置爲10MB大小,而且因爲永久代最大內存和最小內存大小相同,所以沒法擴展。例子代碼以下:
運行一段時間以後,永久代內存不夠,方法區沒法再存放CGLIB建立處理的Class信息,產生方法區OutOfMemoryError。
(5).本機直接內存溢出:
Java虛擬機能夠經過參數-XX:MaxDirectMemorySize設定本機直接內存可用大小,若是不指定,則默認與java堆內存大小相同。JDK中能夠經過反射獲取Unsafe類(Unsafe的getUnsafe()方法只有啓動類加載器Bootstrap才能返回實例)直接操做本機直接內存。經過使用-XX:MaxDirectMemorySize=10M,限制最大可以使用的本機直接內存大小爲10MB,例子代碼以下:
當運行一段時間以後,10MB的本機直接內存被分配光,沒法在進行直接內存分配時,產生OutOfMemoryError。