JVM 深入筆記(2)記憶體溢位場景模擬
JVM 深入筆記(2)各記憶體區溢位場景模擬
- 作者:柳大 · Poechant
- 電郵:zhongchao.ustc#gmail.com (#->@)
- 部落格:blog.csdn.net/poechant
- 日期:Feb. 23st2012
《JVM 深入筆記(1)記憶體區域是如何劃分的?》一文已經介紹了 JVM 對記憶體區域的劃分與管理。在現實的程式設計過程中,會遇到一些 OutOfMemoryError (OOM) 的情形。通過模擬,我們可以直接點中這些場景的本質,從而在紛繁複雜的千萬行程式碼中避免這樣去 coding。導致 OOM 的情況有多種,包括 Java 或 Native Method Stack 的記憶體不足或者棧空間溢位、Heap 記憶體溢位、Non-heap 記憶體溢位、Direct Memory 溢位。
1. Java Method Stack 棧溢位實驗
什麼時候會讓 Java Method Stack 棧溢位啊?棧的基本特點就是 FILO(First In Last Out),如果 in 的太多而 out 的太少,就好 overflow 了。而 Java Method Stack 的功能就是儲存每一次函式呼叫時的“現場”,即為入棧,函式返回就對應著出棧,所以函式呼叫的深度越大,棧就變得越大,足夠大的時候就會溢位。所以模擬 Java Method Stack 溢位,只要不斷遞迴呼叫某一函式就可以。
程式原始碼-1
// Author: Poechant
// Blog: blog.csdn.net/poechant
// Email: zhognchao.ustc#gmail.com (#->@)
// Args: -verbose:gc -Xss128K
package com.sinosuperman.main;
public class Test {
private int stackLength = 0;
public void stackOverflow() {
++stackLength;
stackOverflow();
}
public static void main(String[] args) throws Throwable {
Test test = new Test();
try {
test.stackOverflow();
} catch (Throwable e) {
System.out.println("stack length: " + test.stackLength);
throw e;
}
}
}
執行結果
stack length: 1052
Exception in thread "main" java.lang.StackOverflowError
at com.sinosuperman.main.Test.stackOverflow(Test.java:8)
at com.sinosuperman.main.Test.stackOverflow(Test.java:9)
at com.sinosuperman.main.Test.stackOverflow(Test.java:9)
at com.sinosuperman.main.Test.stackOverflow(Test.java:9)
at com.sinosuperman.main.Test.stackOverflow(Test.java:9)
...
2. Java Method Stack 記憶體溢位實驗
Heap 記憶體溢位
堆是用來儲存物件的,當然物件不一定都存在堆裡(由於逃逸技術的發展)。那麼堆如果溢位了,一定是不能被殺掉的物件太多了。模擬 Heap 記憶體溢位,只要不斷建立物件並保持有引用存在即可。
程式原始碼-2
// Author: Poechant
// Blog: blog.csdn.net/poechant
// Email: zhongchao.ustc#gmail.com (#->@)
// Args: -verbose:gc -Xmx50m -Xms50m
package com.sinosuperman.main;
import java.util.ArrayList;
import java.util.List;
public class Test {
private static class HeapOomObject {
}
public static void main(String[] args) {
List<HeapOomObject> list = new ArrayList<HeapOomObject>();
while (true) {
list.add(new HeapOomObject());
}
}
}
執行結果
[GC 17024K->14184K(49088K), 0.1645899 secs]
[GC 26215K->29421K(49088K), 0.0795283 secs]
[GC 35311K(49088K), 0.0095602 secs]
[Full GC 43400K->37709K(49088K), 0.1636702 secs]
[Full GC 49088K->45160K(49088K), 0.1609499 secs]
[GC 45312K(49088K), 0.0265257 secs]
[Full GC 49088K->49087K(49088K), 0.1656715 secs]
[Full GC 49087K->49087K(49088K), 0.1656147 secs]
[Full GC 49087K->49062K(49088K), 0.1976727 secs]
[GC 49063K(49088K), 0.0287960 secs]
[Full GC 49087K->49087K(49088K), 0.1901410 secs]
[Full GC 49087K->49087K(49088K), 0.1673056 secs]
[Full GC 49087K->316K(49088K), 0.0426515 secs]
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at com.sinosuperman.main.Test.main(Test.java:14)
3. Method Area 記憶體溢位
也就是 Non-heap,是用來儲存 Object Class Data、常量、靜態變數、JIT 編譯後的程式碼等。如果該區域溢位,則說明某種資料建立的實在是太多了。模擬的話,可以不斷建立新的 class,直到溢位為止。
以下程式碼使用到cglib-2.2.2.jar和asm-all-3.0.jar。
程式原始碼-3
package com.sinosuperman.main;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class Test {
static class MethodAreaOomObject {
}
public static void main(String[] args) {
while(true){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(MethodAreaOomObject.class);
enhancer.setUseCache(false);
enhancer.setCallback(new MethodInterceptor() {
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
return proxy.invoke(obj, args);
}
});
enhancer.create();
}
}
}
執行結果
Exception in thread "main" net.sf.cglib.core.CodeGenerationException: java.lang.reflect.InvocationTargetException-->null
at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:237)
at net.sf.cglib.proxy.Enhancer.createHelper(Enhancer.java:377)
at net.sf.cglib.proxy.Enhancer.create(Enhancer.java:285)
at com.sinosuperman.main.Test.main(Test.java:24)
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at net.sf.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:384)
at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:219)
... 3 more
Caused by: java.lang.OutOfMemoryError: PermGen space
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClassCond(ClassLoader.java:631)
at java.lang.ClassLoader.defineClass(ClassLoader.java:615)
... 8 more
4. Runtime Constant Pool in Method Area 記憶體溢位
在執行時產生大量常量就可以實現讓 Method Area 溢位的目的。執行是常量可以用 String 類的 intern 方法,不斷地產生新的常量。
程式原始碼-4
package com.sinosuperman.main;
import java.util.ArrayList;
import java.util.List;
public class Test {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
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.sinosuperman.main.Test.main(Test.java:12)
結語
在實際編碼中要儘量避免此類錯誤。不過大多數程式設計的結構比這裡的示例要複雜的多,使得問題被隱藏。但 JVM 的記憶體溢位問題本質上大都可歸結為以上這幾種情況。
JVM 深入筆記(1)記憶體區域是如何劃分的?
JVM 深入筆記(2)各記憶體區溢位場景模擬
-
轉載請註明來自“柳大的CSDN部落格”:blog.csdn.net/Poechant
-
相關文章
- 深入理解JVM虛擬機器-JVM記憶體區域與記憶體溢位JVM虛擬機記憶體溢位
- JVM——記憶體洩漏與記憶體溢位JVM記憶體溢位
- JVM(2)-Java記憶體區域與記憶體溢位異常JVMJava記憶體溢位
- 對jvm虛擬機器 記憶體溢位的思考JVM虛擬機記憶體溢位
- JVM面試問題系列:深入詳解JVM 記憶體區域及記憶體溢位分析JVM面試記憶體溢位
- 【記憶體洩漏和記憶體溢位】JavaScript之深入淺出理解記憶體洩漏和記憶體溢位記憶體溢位JavaScript
- jvm記憶體設定及記憶體溢位、解決方案JVM記憶體溢位
- Java棧溢位|記憶體洩漏|記憶體溢位Java記憶體溢位
- 深入淺出JVM(十四)之記憶體溢位、洩漏與引用JVM記憶體溢位
- 記憶體溢位記憶體溢位
- Java8虛擬機器(JVM)記憶體溢位實戰Java虛擬機JVM記憶體溢位
- Java記憶體溢位Java記憶體溢位
- 深入理解Java虛擬機器-Java記憶體區域與記憶體溢位異常Java虛擬機記憶體溢位
- 記憶體溢位和記憶體洩露記憶體溢位記憶體洩露
- JVM學習-02-Java記憶體區域與記憶體溢位異常JVMJava記憶體溢位
- Java記憶體區域與記憶體溢位異常(JVM學習系列1)Java記憶體溢位JVM
- 從記憶體洩露、記憶體溢位和堆外記憶體,JVM優化引數配置引數記憶體洩露記憶體溢位JVM優化
- JavaScript之記憶體溢位和記憶體洩漏JavaScript記憶體溢位
- 揭露 FileSystem 引起的線上 JVM 記憶體溢位問題JVM記憶體溢位
- JVM執行緒和記憶體溢位問題排查思路JVM執行緒記憶體溢位
- [Java基礎]記憶體洩漏和記憶體溢位Java記憶體溢位
- JAVA記憶體區域與記憶體溢位異常Java記憶體溢位
- 阿里大佬講解Java記憶體溢位示例(堆溢位、棧溢位)阿里Java記憶體溢位
- java記憶體溢位和記憶體洩漏的區別Java記憶體溢位
- mybatis-plus getOne 記憶體溢位MyBatis記憶體溢位
- return new物件造成溢位記憶體物件記憶體
- 深入理解JVM(一)——JVM記憶體模型JVM記憶體模型
- 深入理解JVM(一)JVM記憶體模型JVM記憶體模型
- Java虛擬機器01——Java記憶體資料區域和記憶體溢位異常Java虛擬機記憶體溢位
- Windbg下使用dump分析記憶體溢位記憶體溢位
- Redis 報”OutOfDirectMemoryError“(堆外記憶體溢位)RedisError記憶體溢位
- 關於 PHP 記憶體溢位的思考PHP記憶體溢位
- 記憶體和棧溢位問題定位記憶體
- php記憶體溢位了怎麼辦?PHP記憶體溢位
- Windows Tomcat 記憶體溢位解決方法WindowsTomcat記憶體溢位
- 深入理解JVM(1)之--JVM記憶體模型JVM記憶體模型
- 深入理解 JVM 之 JVM 記憶體結構JVM記憶體
- 模擬實戰排查堆記憶體溢位(java.lang.OutOfMemoryError: Java heap space)問題記憶體溢位JavaError
- JVM讀書筆記之記憶體管理JVM筆記記憶體