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)
……
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 的内存溢出问题本质上大都可归结为以上这几种情况。
原文地址:http://java.chinaitlab.com/JavaMedia/876985.html
程序源码-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)
……
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 的内存溢出问题本质上大都可归结为以上这几种情况。
原文地址:http://java.chinaitlab.com/JavaMedia/876985.html