Java Method Stack 棧溢出實驗什麼時候會讓 Java Method Stack 棧溢出啊?棧的基本特點就是 FILO(First In Last Out)如果 in 的太多而 out 的太少就好 overflow 了而 Java Method Stack 的功能就是保存每一次函數調用時的現場即為入棧函數返回就對應著出棧所以函數調用的深度越大棧就變得越大足夠大的時候就會溢出所以模擬 Java Method Stack 溢出只要不斷遞歸調用某一函數就可以
程序源碼
// Author Poechant // Blog /poechant // Email zhognchaoustc# (#>@)
// Args verbosegc XssK
package comsinosupermanmain
public class Test {
private int stackLength =
public void stackOverflow() { ++stackLengthstackOverflow()}
public static void main(String[] args) throws Throwable { Test test = new Test()
try { teststackOverflow()} catch (Throwable e) { Systemoutprintln(stack length + teststackLength)throw e}運行結果
stack length Exception in thread main javalangStackOverflowError at comsinosupermanmainTeststackOverflow(Testjava)
at comsinosupermanmainTeststackOverflow(Testjava)
……
Java Method Stack 內存溢出實驗Heap 內存溢出
堆是用來存儲對象的當然對象不一定都存在堆裡(由於逃逸技術的發展)那麼堆如果溢出了一定是不能被殺掉的對象太多了模擬 Heap 內存溢出只要不斷創建對象並保持有引用存在即可
程序源碼
// Author Poechant // Blog /poechant // Email zhongchaoustc# (#>@)
// Args verbosegc Xmxm Xmsm
package comsinosupermanmain
import javautilArrayListimport javautilList
public class Test {
private static class HeapOomObject { }
public static void main(String[] args) { List<HeapOomObject> list = new ArrayList<HeapOomObject>()while (true) { listadd(new HeapOomObject())}運行結果
[GC K>K(K) secs] [GC K>K(K) secs] [GC K(K) secs] [Full GC K>K(K) secs] [Full GC K>K(K) secs] [GC K(K) secs] [Full GC K>K(K) secs] [Full GC K>K(K) secs] [Full GC K>K(K) secs] [GC K(K) secs] [Full GC K>K(K) secs] [Full GC K>K(K) secs] [Full GC K>K(K) secs] Exception in thread main javalangOutOfMemoryError Java heap space at comsinosupermanmainTestmain(Testjava)
Method Area 內存溢出也就是 Nonheap是用來存儲 Object Class Data常量靜態變量JIT 編譯後的代碼等如果該區域溢出則說明某種數據創建的實在是太多了模擬的話可以不斷創建新的 class直到溢出為止
以下代碼使用到 cglibjar 和 asmalljar
程序源碼
package comsinosupermanmain
import javalangreflectMethod
import netsfcglibproxyEnhancerimport netsfcglibproxyMethodInterceptorimport netsfcglibproxyMethodProxy
public class Test { static class MethodAreaOomObject { } public static void main(String[] args) { while(true){ Enhancer enhancer = new Enhancer()enhancersetSuperclass(MethodAreaOomObjectclass)enhancersetUseCache(false)enhancersetCallback(new MethodInterceptor() { public Object intercept(Object obj Method method Object[] argsMethodProxy proxy) throws Throwable { return proxyinvoke(obj args)} })enhancercreate()}運行結果
Exception in thread main reCodeGenerationException javalangreflectInvocationTargetException——>null at reAbstractClassGeneratorcreate(AbstractClassGeneratorjava)
at netsfcglibproxyEnhancercreateHelper(Enhancerjava)
at netsfcglibproxyEnhancercreate(Enhancerjava)
at comsinosupermanmainTestmain(Testjava)
Caused by javalangreflectInvocationTargetException at sunreflectGeneratedMethodAccessorinvoke(Unknown Source)
at sunreflectDelegatingMethodAccessorImplinvoke(DelegatingMethodAccessorImpljava)
at javalangreflectMethodinvoke(Methodjava)
at reReflectUtilsdefineClass(ReflectUtilsjava)
at reAbstractClassGeneratorcreate(AbstractClassGeneratorjava)
…… more Caused by javalangOutOfMemoryError PermGen space at javalangClassLoaderdefineClass(Native Method)
at javalangClassLoaderdefineClassCond(ClassLoaderjava)
at javalangClassLoaderdefineClass(ClassLoaderjava)
…… more Runtime Constant Pool in Method Area 內存溢出在運行時產生大量常量就可以實現讓 Method Area 溢出的目的運行是常量可以用 String 類的 intern 方法不斷地產生新的常量
程序源碼
package comsinosupermanmain
import javautilArrayListimport javautilList
public class Test { public static void main(String[] args) { List<String> list = new ArrayList<String>()int i = while (true) { listadd(StringvalueOf(i++)intern())}運行結果
Exception in thread main javalangOutOfMemoryError PermGen space at javalangStringintern(Native Method)
at comsinosupermanmainTestmain(Testjava)
結語在實際編碼中要盡量避免此類錯誤不過大多數程序設計的結構比這裡的示例要復雜的多使得問題被隱藏但 JVM 的內存溢出問題本質上大都可歸結為以上這幾種情況
From:http://tw.wingwit.com/Article/program/Java/hx/201311/26375.html