JVM內存溢出(OutOfMemoryError異常)

  1.  Java堆java

    java堆用於存儲對象實例,只要不斷的建立對象,而且保證GC Roots到對象之間有可達路徑來避免垃圾回收機制清除這些對象,那麼當對象數量達到最大堆容量限制後就會產生OutOfMemoryError異常。當出現java堆內存溢出時,異常堆棧信息「java.lang.OutOfMemoryError」會跟着進一步提示「Java heap space,以下:多線程

    Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
        at java.util.Arrays.copyOf(Arrays.java:2760)
        at java.util.Arrays.copyOf(Arrays.java:2734)
        at java.util.ArrayList.ensureCapacity(ArrayList.java:167)
        at java.util.ArrayList.add(ArrayList.java:351)
        at com.test.outofmemory.HeapOOM.main(HeapOOM.java:25)框架

     

    解決方式:jvm

        設置Eclipse的jvm參數:測試

-Xms256M -Xmx512M -XX:PermSize=256m -XX:MaxPermSize=512mspa


 

    2.Java虛擬機棧和本地方法棧溢出操作系統

 

    關於java虛擬機棧和本地方法棧,在java虛擬機中描述了兩種異常:線程

  • 若是線程請求的棧深度大於虛擬機容許的最大深度,將拋出StackOverflowError異常代理

  • 若是虛擬機在擴展棧時沒法申請到足夠的內存空間,則拋出OutOfMemoryError異常(OutOfMemoryError unable to cteate new native thread)。code

    解決方式:

     

     

    -Xss:設置每條線程的Statck大小.在JDK1.5之後默認是1M,以前是256K

    拋出StackOverFlow異常:操做系統分配給每一個線程的內存是有限的,機器總內存減去Xmx再減去MaxPermSize,程序計數器佔內存不多忽略,剩下的內存被虛擬機棧和本地方法棧瓜分,每一個線程分到的棧容量越大,分配的線程數就小。正常狀況棧深度1000-2000沒問題,若是是創建更多線程致使的內存溢出,在不能減小線程的狀況下,只能經過減少Xmx和棧容量來換取更多線程。

 

    3.方法區和運行時常量池溢出

 

        若是要向運行時常量池中添加內容,最簡單的作法就是使用String.intern()這個Native方法。該方法的做用是:若是池中已經包含一 個等於此String對象的字符串,則返回表明池中這個字符串的String對象;不然,將此String對象包含的字符串添加到常量池中,而且返回此 String對象的引用。因爲常量池分配在方法區內,咱們能夠經過-XX:PermSize和-XX:MaxPermSize限制方法區的大小,從而間接 限制其中常量池的容量,如代碼所示,運行時常量池致使的內存溢出異常。

/**  * VM Args:-XX:PermSize=10M -XX:MaxPermSize=10M * @author zzm  */ 
 public class RuntimeConstantPoolOOM {   
     public static void main(String[] args) {     
         // 使用List保持着常量池引用,避免Full GC回收常量池行爲     
         List<String> list = new ArrayList<String>();      
         // 10MB的PermSize在integer範圍內足夠產生OOM了      
         int i = 0;      
         while (true) {          
             list.add(String.valueOf(i++).intern());      
         }  
     }  
}

    運行結果:

Exception in thread "main" java.lang.OutOfMemoryError: PermGen space
    at java.lang.String.intern(Native Method)
    at com.test.outofmemory.HeapOOM.main(HeapOOM.java:34)

    從運行結果中能夠看到,運行時常量池溢出,在OutOfMemoryError後面跟隨的提示信息是「PermGen space」,說明運行時常量池屬於方法區(HotSpot虛擬機中的永久代)的一部分。

    方法區用於存放Class的相關信息,如類名、訪問修飾符、常量池、字段描述、方法描述等。對於這些區域的測試,基本的思路是運行時產生大量的類去填滿方法區,直到溢出。

雖然直接使用Java SE API也能夠動態產生類(如反射時的GeneratedConstructorAccessor和動態代理等),但在本次實驗中操做起來比較麻煩。在代碼清單2-8中,筆者藉助CGLib直接操做字節碼運行時生成了大量的動態類。

值得特別注意的是,咱們在這個例子中模擬的場景並不是純粹是一個實驗,這樣的應用常常會出如今實際應用中:當前的不少主流框架,如Spring、 Hibernate,在對類進行加強時,都會使用到CGLib這類字節碼技術,加強的類越多,就須要越大的方法區來保證動態生成的Class能夠加載入內 存。另外,JVM上的動態語言(例如Groovy等)一般都會持續建立類來實現語言的動態性,隨着這類語言的流行,也愈來愈容易遇到與代碼清單2-8類似 的溢出場景。

代碼清單2-8 藉助CGLib使方法區出現內存溢出異常

/**
 * 
 * VM Args: -XX:PermSize=10M -XX:MaxPermSize=10M
 * 
 */

public class JavaMethodAreaOOM {
    public static void main(String[] args) {
        while (true) {
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(OOMObject.class);
            enhancer.setUseCache(false);
            enhancer.setCallback(new MethodInterceptor() {
                public Object intercept(Object obj, Method method,
                        Object[] args, MethodProxy proxy) throws Throwable {
                    return proxy.invokeSuper(obj, args);
                }
            });
            enhancer.create();
        }
    }
    static class OOMObject {
    }
}

 

運行結果:

 

Caused by: java.lang.OutOfMemoryError: PermGen space  

at java.lang.ClassLoader.defineClass1(Native Method)  

at java.lang.ClassLoader.defineClassCond(ClassLoader.java:632)  

at java.lang.ClassLoader.defineClass(ClassLoader.java:616)  ... 8 more

方法區溢出也是一種常見的內存溢出異常,一個類要被垃圾收集器回收掉,斷定條件是比較苛刻的。在常常動態生成大量Class的應用中,須要特別注意類的回 收情況。這類場景除了上面提到的程序使用了CGLib字節碼加強和動態語言以外,常見的還有:大量JSP或動態產生JSP文件的應用(JSP第一次運行時 須要編譯爲Java類)、基於OSGi的應用(即便是同一個類文件,被不一樣的加載器加載也會視爲不一樣的類)等。

 

解決方式:

-PermSize :方法區的初始容量,默認是物理內存的1/64

-MaxPermSize :最大方法區容量。

 

4.本地直接內存溢出

 

    並非虛擬機運行時數據區的一部分。JDK1.4中引入了NIO類,引入了一種基於通道與緩衝區的I/O方式,可使用Native直接分配堆外內存,避免了再Java堆和Native堆中來回複製數據。

不會受到Java堆內存限制,但會受到機器總內存的限制。

若是如法申請到足夠的空間拋出OutOfMemoryError。

 

解決方式:-XX:MaxDirectMemorySize 本機直接內存大小,若是不指定,則與Xmx同樣。

相關文章
相關標籤/搜索