Java記憶體溢位情況
在Java執行時資料區中,除了Program Counter Register(程式計數器)之外,其他幾個資料區中均可能發生OutOfMemoryError,俗稱OOM。
1.Java堆溢位
堆主要是用於物件建立時記憶體的分配,只要我們不斷建立物件,並且這些物件在GC時不會被回收掉,則會發生Java堆記憶體溢位。我們通過以下程式來模擬Java堆溢位的情況:
首先配置虛擬機器引數,將堆大小設定為20M並且不可擴充套件:
-verbose:gc -Xms20M -Xmx20M -XX:+PrintGCDetails
public class Test {
public static class Obj {
}
public static void main(String[] args) throws Exception {
List<Obj> list = new ArrayList<Obj>();
while(true) {
//迴圈建立物件,並且物件並不能被回收
list.add(new Obj());
}
}
}
執行結果如下:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:2245)
at java.util.Arrays.copyOf(Arrays.java:2219)
at java.util.ArrayList.grow(ArrayList.java:242)
at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:216)
at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:208)
at java.util.ArrayList.add(ArrayList.java:440)
at Test.main(Test.java:13)
Java堆記憶體溢位是最常見的記憶體溢位情況,出現Java堆的OOM時,異常棧資訊一般會有java.lang.OutOfMemoryError: Java heap space。
2.虛擬機器棧溢位
當執行緒執行一個方法時,java虛擬機器會建立一個新的棧幀(stack frame),並壓入到該執行緒的棧中,只要這個方法沒有返回,這個棧幀就一直存在於棧中。如果方法巢狀呼叫層次太多(如上面的遞迴呼叫),則該執行緒棧中的棧幀會越來越多,並且方法都沒有結束返回,這些棧幀也不會出棧,最終導致這個執行緒的棧中所有棧幀的大小總和大於-Xss設定的值,從而產生StackOverflowError異常。
本地方法棧與虛擬機器棧類似,在這裡會有2種溢位情況:
- 如果執行緒請求的棧深度大於虛擬機器所允許的最大深度,則丟擲StackOverflowError異常;
- 如果虛擬機器在擴充套件棧時無法申請到足夠的記憶體空間,則丟擲OutOfMemoryError異常。
我們來模擬棧溢位情況,首先配置虛擬機器引數,設定棧大小為160k:
-verbose:gc -Xss160k -XX:+PrintGCDetails
public class Test {
private int l = 1;
public void callMethod() {
System.out.println(l);
l++;
callMethod();
}
public static void main(String[] args) throws Exception {
Test t = new Test();
try {
t.callMethod();
} catch(Exception e) {
System.out.println("stack length : " + t.l);
throw e;
}
}
}
執行結果如下:
Exception in thread "main" java.lang.StackOverflowError
at Test.callMethod(Test.java:11)
at Test.callMethod(Test.java:12)
at Test.callMethod(Test.java:12)
......
......
在單執行緒下測試以上程式碼時,發現只會丟擲StackOverflowError異常。
3.方法區的溢位
方法區用於存放Class資訊、常量等,方法區的記憶體溢位主要有2種情況:
- 現在的很多主流框架如Spring,會在執行時生成大量的增強類,增強的類越多,就需要越大的方法區來儲存動態生成的Class資訊,因此也越容易發生記憶體溢位。
- 執行時常量池記憶體溢位。
我們可以使用String.intern()方法不斷生成字串常量來模擬記憶體溢位,同樣先設定方法區的記憶體大小。
-verbose:gc -XX:PermSize=4M -XX:MaxPermSize=4M -XX:+PrintGCDetails
public class Test {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
int i = 0;
while(true) {
System.out.println(i);
list.add(String.valueOf(i++).intern());
}
}
}
執行結果如下:
Exception in thread "main" java.lang.OutOfMemoryError: PermGen space
at java.lang.String.intern(Native Method)
......
從異常棧資訊中可以看到,在java.lang.OutOfMemoryError後面跟隨的是”PermGen space”,這裡說明常量池是屬於虛擬機器中永久代的一部分。
4.小結
本文主要模擬了不同的記憶體區域出現記憶體溢位的情況,當我們自己的應用程式出現記憶體溢位時,就能根據異常資訊定位到記憶體溢位的程式碼所在。
相關文章
- Java棧溢位|記憶體洩漏|記憶體溢位Java記憶體溢位
- Java記憶體溢位Java記憶體溢位
- 異常、堆記憶體溢位、OOM的幾種情況記憶體溢位OOM
- java 程式記憶體溢位Java記憶體溢位
- 記憶體溢位記憶體溢位
- 阿里大佬講解Java記憶體溢位示例(堆溢位、棧溢位)阿里Java記憶體溢位
- JAVA記憶體區域與記憶體溢位異常Java記憶體溢位
- [Java基礎]記憶體洩漏和記憶體溢位Java記憶體溢位
- JBOSS記憶體溢位記憶體溢位
- 記憶體溢位:native溢位 和 上層溢位記憶體溢位
- 【轉】java中的記憶體溢位和記憶體洩漏Java記憶體溢位
- java記憶體溢位和記憶體洩漏的區別Java記憶體溢位
- 記憶體溢位和記憶體洩露記憶體溢位記憶體洩露
- 記憶體洩漏和記憶體溢位記憶體溢位
- 05記憶體情況記憶體
- WebLogic: 記憶體溢位Web記憶體溢位
- 記憶體溢位問題記憶體溢位
- 記憶體溢位的分析記憶體溢位
- JVM(2)-Java記憶體區域與記憶體溢位異常JVMJava記憶體溢位
- Java記憶體溢位(OOM)異常完全指南Java記憶體溢位OOM
- Java虛擬機器4:記憶體溢位Java虛擬機記憶體溢位
- 【記憶體洩漏和記憶體溢位】JavaScript之深入淺出理解記憶體洩漏和記憶體溢位記憶體溢位JavaScript
- JVM——記憶體洩漏與記憶體溢位JVM記憶體溢位
- 手動寫java記憶體溢位 java.lang.StackOverflowErrorJava記憶體溢位Error
- Android記憶體溢位分析Android記憶體溢位
- 記憶體溢位的問題記憶體溢位
- Flume記憶體溢位錯誤記憶體溢位
- JNI練習-記憶體溢位記憶體溢位
- Java記憶體溢位OutOfMemoryError的產生與排查Java記憶體溢位Error
- Java服務假死後續之記憶體溢位Java記憶體溢位
- Java記憶體溢位的詳細解決方案Java記憶體溢位
- JavaScript之記憶體溢位和記憶體洩漏JavaScript記憶體溢位
- 【深入Java虛擬機器】之一:Java記憶體區域與記憶體溢位Java虛擬機記憶體溢位
- 記憶體洩漏與記憶體溢位神比較記憶體溢位
- 直播平臺搭建,Java 記憶體溢位的排查方法Java記憶體溢位
- java 讀 大檔案excel 記憶體溢位 解決JavaExcel記憶體溢位
- Java EasyExcel 匯出報記憶體溢位如何解決JavaExcel記憶體溢位
- Java記憶體區域與記憶體溢位異常(JVM學習系列1)Java記憶體溢位JVM