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虛擬機》
本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!