jvm(2)-OutOfMemoryError 异常(内存溢出异常)
生活随笔
收集整理的這篇文章主要介紹了
jvm(2)-OutOfMemoryError 异常(内存溢出异常)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
【0】README
0.1)本文轉自 深入理解 jvm, 旨在學習?OutOfMemoryError 異常(內存溢出異常) 的觸發類型;
0)準備知識 0.1)除了程序計數器外,虛擬機內存的其他幾個運行時區域(方法區+虛擬機棧+本地方法棧+java堆)都有發生 OutOfMemoryError異常的可能性; 0.2)如何設置Eclipse 的 VM 參數?
1)java堆內存溢出異常測試 1.1)運行結果(運行參數 -Xms20M -Xmx20M -XX:+HeapDumpOnOutOfMemoryError) package com.jvm.chapter2;import java.util.ArrayList; import java.util.List;/*** VM Args:-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError* @author zzm*/ public class HeapOOM {static class OOMObject {}public static void main(String[] args) {List<OOMObject> list = new ArrayList<OOMObject>();while (true) {list.add(new OOMObject());}} }<strong> </strong> 1.2)solution:?通過內存映像分析工具(如 Eclipse Memory Analyzer) 對 dump(轉儲) 出來的堆轉儲快照進行分析,重點是確認內存中的對象是否是有必要的,也就是要先分清楚是出現了內存泄露(Memory Leak) 還是內存溢出(Memory Overflow);
2)虛擬機棧和本地方法棧溢出 2.1)?HotSpot 虛擬機中并不區分虛擬機棧和本地方法棧; 2.2)使用 -Xss 參數減少棧內存容量。結果: 拋出StackOverflowError 異常,異常出現時輸出的堆棧深度相應縮小; 2.3)運行結果:(運行參數 -Xss128k) package com.jvm.chapter2;/*** VM Args:-Xss128k* @author zzm*/ public class JavaVMStackSOF {private int stackLength = 1;public void stackLeak() {stackLength++;stackLeak();}public static void main(String[] args) throws Throwable {JavaVMStackSOF oom = new JavaVMStackSOF();try {oom.stackLeak();} catch (Throwable e) {System.out.println("stack length:" + oom.stackLength);throw e;}} } 2.4)定義了大量的本地變量,增大此方法幀中本地變量表的長度。結果: 拋出StackOverflowError 異常時輸出的堆棧深度相應縮小;
3)方法區和運行時常量池溢出 3.0)String.intern() :是一個Native方法,它的作用是:?如果字符串常量池中已經包含一個等于此String 對象的字符串,則返回代表池中這個字符串的String對象;否則,將此String對象包含的字符串添加到常量池中,并且返回此String 對象 的引用; 3.1)由于常量池分配在永久代內,通過 -XX:PermSize 和 -XX:MaxPermSize 限制方法區大小,從而間接限制其中常量池的容量; 3.2)運行參數(-XX:PermSize=10M -XX:MaxPermSize=10M) Attention)沒有拋出異常,因為? Java HotSpot(TM) 64-Bit Server VM warning: ignoring option PermSize=1M; support was removed in 8.0 Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=1M; support was removed in 8.0
3.3)測試 String.intern方法: package com.jvm.chapter2;public class RuntimeConstantPoolOOM {public static void main(String[] args){String str1 = new StringBuilder("中國").append("釣魚島").toString();System.out.println(str1.intern() == str1);// trueString str2 = new StringBuilder("ja").append("va").toString();System.out.println(str2.intern() == str2);// false} } 對上圖的分析)Analysis: A1)在jdk 1.6中,會得到兩個false。? ?因為在 jdk1.6中,intern 方法會把首次遇到的字符串實例copy 到永久代中,返回的也是永久代中這個字符串市實例的引用,而StringBuilder 創建的字符串實例在 java堆上,所以必然不是同一個引用; A2)在jdk1.7中,會得到一個true和一個false。因為在 jdk1.7中的 intern 方法不會copy實例,只是在常量池中記錄首次出現的實例引用,因此intern() 方法的引用和由StringBuilder 創建的那個字符串實例是同一個。對str2 比較返回false 是因為“java”這個字符串在執行 StringBuilder.toString()之前已經出現過了,字符串常量池已經有它的引用了,不符合“首次出現原則”,而“計算機軟件”這個字符串則是首次出現,因此返回true;
4)本機直接內存溢出 4.1)DirectMemory容量:?可以通過-XX:MaxDirectMemorySize 指定,如果不指定,則默認與java 堆最大值(-Xmx指定)一樣;
0)準備知識 0.1)除了程序計數器外,虛擬機內存的其他幾個運行時區域(方法區+虛擬機棧+本地方法棧+java堆)都有發生 OutOfMemoryError異常的可能性; 0.2)如何設置Eclipse 的 VM 參數?
1)java堆內存溢出異常測試 1.1)運行結果(運行參數 -Xms20M -Xmx20M -XX:+HeapDumpOnOutOfMemoryError) package com.jvm.chapter2;import java.util.ArrayList; import java.util.List;/*** VM Args:-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError* @author zzm*/ public class HeapOOM {static class OOMObject {}public static void main(String[] args) {List<OOMObject> list = new ArrayList<OOMObject>();while (true) {list.add(new OOMObject());}} }<strong> </strong> 1.2)solution:?通過內存映像分析工具(如 Eclipse Memory Analyzer) 對 dump(轉儲) 出來的堆轉儲快照進行分析,重點是確認內存中的對象是否是有必要的,也就是要先分清楚是出現了內存泄露(Memory Leak) 還是內存溢出(Memory Overflow);
2)虛擬機棧和本地方法棧溢出 2.1)?HotSpot 虛擬機中并不區分虛擬機棧和本地方法棧; 2.2)使用 -Xss 參數減少棧內存容量。結果: 拋出StackOverflowError 異常,異常出現時輸出的堆棧深度相應縮小; 2.3)運行結果:(運行參數 -Xss128k) package com.jvm.chapter2;/*** VM Args:-Xss128k* @author zzm*/ public class JavaVMStackSOF {private int stackLength = 1;public void stackLeak() {stackLength++;stackLeak();}public static void main(String[] args) throws Throwable {JavaVMStackSOF oom = new JavaVMStackSOF();try {oom.stackLeak();} catch (Throwable e) {System.out.println("stack length:" + oom.stackLength);throw e;}} } 2.4)定義了大量的本地變量,增大此方法幀中本地變量表的長度。結果: 拋出StackOverflowError 異常時輸出的堆棧深度相應縮小;
3)方法區和運行時常量池溢出 3.0)String.intern() :是一個Native方法,它的作用是:?如果字符串常量池中已經包含一個等于此String 對象的字符串,則返回代表池中這個字符串的String對象;否則,將此String對象包含的字符串添加到常量池中,并且返回此String 對象 的引用; 3.1)由于常量池分配在永久代內,通過 -XX:PermSize 和 -XX:MaxPermSize 限制方法區大小,從而間接限制其中常量池的容量; 3.2)運行參數(-XX:PermSize=10M -XX:MaxPermSize=10M) Attention)沒有拋出異常,因為? Java HotSpot(TM) 64-Bit Server VM warning: ignoring option PermSize=1M; support was removed in 8.0 Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=1M; support was removed in 8.0
3.3)測試 String.intern方法: package com.jvm.chapter2;public class RuntimeConstantPoolOOM {public static void main(String[] args){String str1 = new StringBuilder("中國").append("釣魚島").toString();System.out.println(str1.intern() == str1);// trueString str2 = new StringBuilder("ja").append("va").toString();System.out.println(str2.intern() == str2);// false} } 對上圖的分析)Analysis: A1)在jdk 1.6中,會得到兩個false。? ?因為在 jdk1.6中,intern 方法會把首次遇到的字符串實例copy 到永久代中,返回的也是永久代中這個字符串市實例的引用,而StringBuilder 創建的字符串實例在 java堆上,所以必然不是同一個引用; A2)在jdk1.7中,會得到一個true和一個false。因為在 jdk1.7中的 intern 方法不會copy實例,只是在常量池中記錄首次出現的實例引用,因此intern() 方法的引用和由StringBuilder 創建的那個字符串實例是同一個。對str2 比較返回false 是因為“java”這個字符串在執行 StringBuilder.toString()之前已經出現過了,字符串常量池已經有它的引用了,不符合“首次出現原則”,而“計算機軟件”這個字符串則是首次出現,因此返回true;
4)本機直接內存溢出 4.1)DirectMemory容量:?可以通過-XX:MaxDirectMemorySize 指定,如果不指定,則默認與java 堆最大值(-Xmx指定)一樣;
總結
以上是生活随笔為你收集整理的jvm(2)-OutOfMemoryError 异常(内存溢出异常)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 备案的时候(解备案时间)
- 下一篇: 让CentOS能用yum自动安装rar和