Java内存区域及内存溢出

发布时间:2019-11-19 发布网站:脚本宝典
脚本宝典收集整理的这篇文章主要介绍了Java内存区域及内存溢出脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。

堆溢出

Java堆用于存储对象实例,只要不断地创建对象,并且保证GC Roots到对象之间有可达路径避免垃圾回收,当到达最大堆的容量限制后就会产生Java.lang.OutOfMemoryError.

/**  * VM Options:  * -Xms20M  * -Xmx20M  * -XX:+HeapDumpOnOutOfMemoryError  */ public class HeapOOM{     static class OOMObject{}          public static void main(String[] args){         List<OOMObject> list = new ArrayList<OOMObject>();         while(true){             list.add(new OOMObject());         }     } }

结果:
GC多次执行后触发OutOfMemoryError.

Java内存区域及内存溢出

栈溢出

关于虚拟机栈,在Java规范中描述了两种异常:

  1. 如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常。
  2. 如果虚拟机在扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常。

然而,在单线程下,虚拟机在栈空间不足时会尝试扩展栈空间,因此,当无法继续分配时,到底是内存太小,还是已使用的栈空间太大,其实是一回事。在实验中,单线程环境下,只会抛出StackOverflowError异常。

/**  * VM Option:  * -Xss160K  */ public class JavaVMStackSOF{     PRivate int stackLength = 1;     public void stackLeak(){         stackLength++;         stackLeak();     }     public static void main(String[] args) throws Throwable{         JavaVMStackSOF oom = new JavaVMStackSOF();         try{             oom.stackLeak();         }         catch(Throwable e){             System.out.println("Stack length:" + oom.stackLength);             throw e;         }     } }

结果:

Java内存区域及内存溢出

操作系统分配给每个进程的内存是有限制的,通常为操作系统限制总内存-最大堆容量(Xmx)-最大方法区容量(MaxpermSize)-程序计数器消耗。每个线程分配到的栈容量越大,可以建立的线程数目越小。

/**  * VM Options:  * -Xss2M  */ public class JavaVMStackOOM{     private void dontStop(){         while(true){}     }          public void stackLeakByThread(){         while(true){             Thread thread = new Thread(new Runnable(){                 @override                 public void run(){                     dontStop();                 }             });             thread.start();         }     }          public static void main(String[] args) throws Throwable{         JavaVMStackOOM oom = new JavaVMStackOOM();         oom.stackLeakByThread();     } }

结果:
Exception in thread "main" java.lang.outOfMemoryError: unable to create new native thread

运行时常量池溢出

运行时常量池在JDK 1.6及之前版本中在方法区中,在1.7及之后转移至堆空间。在JDK 1.6及之前版本中可以通过限制方法区大小,从而间接限制运行时常量池大小。

/**  * ONLY WORKS BEFORE JDK 1.7  * VM Options:  * -XX:PermSize=10M  * -XX:MaxPermSize=10M public class RuntimeConstantPoolOOM{     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

方法区溢出

方法区用于存放Class相关信息,因此要使得方法区溢出,除了在JDK 1.7之前使运行时常量池溢出外,基本的思路是运行时生成大量的类去填满方法区。
结果
Exception in thread "main" java.lang.OutOfMemoryError:PermGen space

直接内存(DirectMemory)溢出

直接内存不是虚拟机运行时数据区的一部分。在JDK 1.4中新加入了NIO(New Input/Output)类,引入了一种基于通道(Channel)与缓冲区(Buffer)的I/O方式,使用Native函数库直接分配堆外内存。
DirectMemory容量可通过-XX: MaxDirectMemorySize指定,如果不指定,则默认与Java堆最大值一样(-Xmx)。直接通过allocateMemory可以造成本机内存溢出。

结果:
Exception in thread "main" java.lang.OutOfMemoryError
直接内存溢出的一个特征是Heap Dump文件中不会看先明显的异常指示。如果OOM之后Dump文件很小,而程序中又直接或间接使用了DIO,就应该检查是否直接内存溢出。

String.intern()

String.intern()是一个Native方法,作用是:如果字符串常量池中已经包含一个等于此String对象的字符串,则返回代表池中这个字符串的String对象,否则,将此String对象包含的字符串添加到常量池中,并且返回此String对象的引用。

public class RuntimeConstantPoolOOM{     public static void main(String[] args){         String str1 = new StringBuilder("计算机").append("软件").toString();         System.out.println(str1.intern() == str1);//JDK 1.6 false JDK 1.7 true                  String str2 = new StringBuilder("ja").append("va").toString();         System.out.println(str2.intern() == str2);//JDK 1.6 false JDK 1.7 true     } }

在JDK 1.6中,intern()方法会把首次遇到的字符串实例复制到永久代(方法区运行时常量池),返回的是这个永久代中这个字符串实例的引用,而由StringBuilder创建的字符串实例在Java堆上,所以必然不是同一个引用。
在JDK 1.7中,intern()实现不会再复制,只是在常量池中记录首次出现的实例引用,因此intern()返回的引用和由StringBuilder创建的那个字符串实例是同一个。

小节

内存区域 描述 VM Option 异常
程序计数器
虚拟机栈 存放编译器可知的各种基本类型,对象引用和returnAddress类型 -Xss160K 每个线程的栈大小 StackOverflowError/OutOfMemoryError
Java堆 存放对象实例 -Xms10M 最大值
-Xmx20M 最小值
OutOfMemory: Java heap space
运行时常亮池 存放编译期生成的字面量和符号引用,运行期也能放入常量池(string.intern())。JDK 1.7之前在方法区中,JDK 1.7及之后移至堆中 随方法区或堆设置 OutOfMemoryError
方法区 存储虚拟机加载的类信息、常亮、静态变量、即时编译器编译后的代码等数据,又称为永久代(Permanent Generation) -XX:PermSize=10M 初始值
-XX:MaxPermSize=20M 最大值
OutOfMemoryError: PermGen space
直接内存 在JDK 1.4中加入NIO类,直接分配堆外内存 -XX:MaxDirectMemorySize=10M,
如果不指定默认与-Xmx一样
OutOfMemoryError

脚本宝典总结

以上是脚本宝典为你收集整理的Java内存区域及内存溢出全部内容,希望文章能够帮你解决Java内存区域及内存溢出所遇到的问题。

如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典推荐好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。