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 的内存溢出问题本质上大都可归结为以上这几种情况 |