Java內存區域與內存溢出異常

Java虛擬機運行時數據區

程序計數器

程序計數器能夠看做是當前線程所執行的字節碼的行號指示器
線程私有

異常:
惟一一個java虛擬機規範中沒有規定任何OutOfMemoryError狀況的區域

Java虛擬機棧

線程私有,生命週期和線程相同
虛擬機棧描述的是Java方法執行的內存模型:每一個方法在執行的同時會建立一個棧幀用於存儲局部變量表、操做數棧、動態連接、方法出口等信息。局部變量表存放了編譯期可知的各類基本數據類型、對象引用。

異常:
線程請求的棧深度大於虛擬機所容許的深度,將拋出StackOverFlowError異常
若是虛擬機棧能夠動態擴展,若是擴展沒法申請到足夠的內存,就會拋出OOM
/**
 * 虛擬棧遞歸調用棧溢出(StackOverFlowError)
 * VM Args:-Xss512k
 */
public class JavaVMStackSOF {
    private int stackLenqth = 1;

    public void stackLeek() {
        stackLenqth++;
        //遞歸調用
        stackLeek();
    }

    public static void main(String[] args) {
        JavaVMStackSOF stackSOF = new JavaVMStackSOF();
        stackSOF.stackLeek();
    }
}
//結果
Exception in thread "main" java.lang.StackOverflowError
	at outofmemory.JavaVMStackSOF.stackLeek(JavaVMStackSOF.java:11)
/**
 * 建立線程致使OOM
 * VM Args: -Xss2M
 */
public class JavaVMStackOOM {
    private void  dontStop(){
        while (true){

        }
    }

    public void stackLeakByThread(){
        while (true){
            Thread thread = new Thread(new Runnable() {
                public void run() {
                    dontStop();
                }
            });
            thread.start();
        }
    }

    public static void main(String[] args) {
        JavaVMStackOOM stackOOM = new JavaVMStackOOM();
        stackOOM.stackLeakByThread();

    }
}
//結果
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

本地方法棧

全部線程共享
本地方法棧和Java虛擬棧類似,Java虛擬機棧爲虛擬機執行Java方法(字節碼)服務,本地方法棧爲虛擬機
用到的native方法服務。
HotSpot虛擬機將虛擬機棧和本地方法棧合二爲一

Java堆

全部的對象實例和數組都要在堆上分配
Java堆是垃圾器管理的主要區域

異常:
堆中沒有內存完成實例分配,而且堆沒法在擴展的時,就會拋出OOM
/**
 * 堆內存溢出
 * VM Args: -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError
 */
public class HeapOOM {
    static class OOMObject {
    }

    public static void main(String[] args) {
        List<OOMObject> list = new ArrayList<OOMObject>();
        while (true) {//循環建立對象
            list.add(new OOMObject());
        }
    }
}
//運行結果
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

方法區

全部線程共享
用於存儲已被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯後的代碼等數據

異常:
方法區沒法知足內存分配需求時,就會拋出OOM

運行時常量池

方法區的一部分
用於存放編譯期生成的各類字面量和符號引用
Java並不要求常量必定要是編譯期才能產生,運行期間也可能將新的常量放入池中,好比String類的intern()方法

異常:
運行時常量池做爲方法區的一部分,天然收到方法去內存的限制,常量池沒法申請到內存拋出OOM
/**
 * 運行是常量池溢出
 * VM Args: -XX:PermSize=10M -XX:MaxPermSize=10M
 */
public class RuntimeConstantPoolOOM {
    public static void main(String[] args) {
        List<String> stringList = new ArrayList<String>();
        int i = 1;
        while (true){
            stringList.add(String.valueOf(i++));
        }
    }
}
//結果
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option PermSize=10M; 
support was removed in 8.0
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=10M; 
support was removed in 8.0
// 分析
我使用的時jdk8.0發生如上錯誤,這個說明永久代已經在java8.0中被移除,被元空間替代。
關於爲啥要移除替代本篇不累贅。若是使用的jdk8.0一下版本則會出現OOM:PermGen space
這樣能夠證實常量池屬於方法區
//VM Args:-XX:MaxMetaspaceSize=2M(這樣設置元空間大小 )

直接內存

直接內存不是虛擬機運行時數據區的一部分,也不是Java虛擬機規範中定義的內存區域
NIO可使用Native函數庫直接分配堆外內存


異常:
本機內存不足拋出OOM

 參考資料:《深刻理解Java虛擬機》java

相關文章
相關標籤/搜索