写代码实现栈溢出、堆溢出、永久代溢出、直接内存溢出

您所在的位置:网站首页 java怎么写一个方法的代码 写代码实现栈溢出、堆溢出、永久代溢出、直接内存溢出

写代码实现栈溢出、堆溢出、永久代溢出、直接内存溢出

2024-07-12 11:01| 来源: 网络整理| 查看: 265

栈溢出(StackOverflowError)堆溢出(OutOfMemoryError:Java heap space)永久代溢出(OutOfMemoryError: PermGen space)直接内存溢出 一、堆溢出

创建对象时如果没有可以分配的堆内存,JVM就会抛出OutOfMemoryError:java heap space异常。堆溢出实例:

/** * 堆溢出 * * VM Args: -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError */ public class Heap { public static void main(String[] args) { List list = new ArrayList(); int i = 0; while (true) { list.add(new byte[5 * 1024 * 1024]); System.out.println("分配次数:" + (++i)); } } } 二、栈溢出

栈空间不足时,需要分下面两种情况处理:

线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError 虚拟机在扩展栈深度时无法申请到足够的内存空间,将抛出OutOfMemberError 附:当前大部分的虚拟机栈都是可动态扩展的。

1、栈空间不足——StackOverflowError实例

/** * 栈溢出 */ public class Stack { public static void main(String[] args) { new Stack().test(); } public void test() { test(); } } 2、栈空间不足——OutOfMemberError实例  单线程情况下,不论是栈帧太大还是虚拟机栈容量太小,都会抛出StackOverflowError,导致单线程情境下模拟栈内存溢出不是很容易,不过通过不断的建立线程倒是可以产生内存溢出异常。 public class StackSOFTest { int depth = 0; public void sofMethod(){ depth ++ ; sofMethod(); } public static void main(String[] args) { StackSOFTest test = null; try { test = new StackSOFTest(); test.sofMethod(); } finally { System.out.println("递归次数:"+test.depth); } } } 执行结果: 递归次数:982 Exception in thread "main" java.lang.StackOverflowError at com.ghs.test.StackSOFTest.sofMethod(StackSOFTest.java:8) at com.ghs.test.StackSOFTest.sofMethod(StackSOFTest.java:9) at com.ghs.test.StackSOFTest.sofMethod(StackSOFTest.java:9) ……后续堆栈信息省略 三、永久代溢出

永久代溢出可以分为两种情况,第一种是常量池溢出,第二种是方法区溢出。

1、永久代溢出——常量池溢出  要模拟常量池溢出,可以使用String对象的intern()方法。如果常量池包含一个此String对象的字符串,就返回代表这个字符串的String对象,否则将String对象包含的字符串添加到常量池中。

public class ConstantPoolOOMTest { /** * VM Args:-XX:PermSize=10m -XX:MaxPermSize=10m * @param args */ public static void main(String[] args) { List list = new ArrayList(); int i=1; try { while(true){ list.add(UUID.randomUUID().toString().intern()); i++; } } finally { System.out.println("运行次数:"+i); } } }

因为在JDK1.7中,当常量池中没有该字符串时,JDK7的intern()方法的实现不再是在常量池中创建与此String内容相同的字符串,而改为在常量池中记录Java Heap中首次出现的该字符串的引用,并返回该引用。  简单来说,就是对象实际存储在堆上面,所以,让上面的代码一直执行下去,最终会产生堆内存溢出。  下面我将堆内存设置为:-Xms5m -Xmx5m,执行上面的代码,运行结果如下:

运行次数:58162 Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at java.lang.Long.toUnsignedString(Unknown Source) at java.lang.Long.toHexString(Unknown Source) at java.util.UUID.digits(Unknown Source) at java.util.UUID.toString(Unknown Source) at com.ghs.test.ConstantPoolOOMTest.main(ConstantPoolOOMTest.java:18)

2、永久代溢出——方法区溢出  方法区存放Class的相关信息,下面借助CGLib直接操作字节码,生成大量的动态类。

public class MethodAreaOOMTest { public static void main(String[] args) { int i=0; try { while(true){ Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(OOMObject.class); enhancer.setUseCache(false); enhancer.setCallback(new MethodInterceptor() { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { return proxy.invokeSuper(obj, args); } }); enhancer.create(); i++; } } finally{ System.out.println("运行次数:"+i); } } static class OOMObject{ } } 运行结果: 运行次数:56 Exception in thread "main" Exception: java.lang.OutOfMemoryError thrown from the UncaughtExceptionHandler in thread "main" 四、直接内存溢出

DirectMemory可以通过-XX:MaxDirectMemorySize指定,如果不指定,默认与Java堆的最大值(-Xmx指定)一样。  NIO会使用到直接内存,你可以通过NIO来模拟,在下面的例子中,跳过NIO,直接使用UnSafe来分配直接内存。

public class DirectMemoryOOMTest { /** * VM Args:-Xms20m -Xmx20m -XX:MaxDirectMemorySize=10m * @param args */ public static void main(String[] args) { int i=0; try { Field field = Unsafe.class.getDeclaredFields()[0]; field.setAccessible(true); Unsafe unsafe = (Unsafe) field.get(null); while(true){ unsafe.allocateMemory(1024*1024); i++; } } catch (Exception e) { e.printStackTrace(); }finally { System.out.println("分配次数:"+i); } } } 运行结果: Exception in thread "main" java.lang.OutOfMemoryError at sun.misc.Unsafe.allocateMemory(Native Method) at com.ghs.test.DirectMemoryOOMTest.main(DirectMemoryOOMTest.java:20) 分配次数:27953

总结:  栈内存溢出:程序所要求的栈深度过大。  堆内存溢出:分清内存泄露还是 内存容量不足。泄露则看对象如何被 GC Root 引用,不足则通过调大-Xms,-Xmx参数。  永久代溢出:Class对象未被释放,Class对象占用信息过多,有过多的Class对象。  直接内存溢出:系统哪些地方会使用直接内存。

参考:

https://blog.csdn.net/u011983531/article/details/63250882

https://www.cnblogs.com/panxuejun/p/5882424.html



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3