模拟JVM内存溢出
来源:互联网 发布:如何下载excel2010软件 编辑:程序博客网 时间:2024/05/21 22:48
一、Java堆溢出
1、配置参数:-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError
上面的参数限定了堆的大小为20M不可扩展,XX:+HeapDumpOnOutOfMemoryError用来生成dump快照文件,当内存溢出时,可以用来分析。JDK版本为JDK1.7,开发工具为myEclipse,参数通过myeclipse的run configrations 的arguments选项来配置
public class HeapOOM {static class OOMObject{}public static void main(String[] args) {List<OOMObject> list = new ArrayList<HeapOOM.OOMObject>();while(true){list.add(new OOMObject());}}}运行结果:
java.lang.OutOfMemoryError: Java heap spaceDumping heap to java_pid5772.hprof ...Heap dump file created [27893534 bytes in 0.101 secs]Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
二、虚拟机栈和本地方法栈溢出
方案一:指定了每条现程的堆栈大小,-Xss 128k
public class JavaStackSOF {private int stackLength = 1;public void stackLeak(){stackLength ++;stackLeak();}public static void main(String[] args) throws Throwable {JavaStackSOF javaStackSOF = new JavaStackSOF();try{javaStackSOF.stackLeak();}catch (Throwable e) {System.out.println("stacklength="+javaStackSOF.stackLength);throw e;}}}
运行结果
stacklength=993Exception in thread "main" java.lang.StackOverflowError at JavaStackSOF.stackLeak(JavaStackSOF.java:9) at JavaStackSOF.stackLeak(JavaStackSOF.java:12) at JavaStackSOF.stackLeak(JavaStackSOF.java:12) at JavaStackSOF.stackLeak(JavaStackSOF.java:12) at JavaStackSOF.stackLeak(JavaStackSOF.java:12) at JavaStackSOF.stackLeak(JavaStackSOF.java:12)
方案二:指定了每条现程的堆栈大小,-Xss 128k,同时增加栈中的局部变量
public class JavaStackSOF {private int stackLength = 1;private int tempData = 1;int temp = 2;public void stackLeak(){stackLength ++;tempData++;//增加栈中的局部变量temp++;stackLeak();}public static void main(String[] args) throws Throwable {JavaStackSOF javaStackSOF = new JavaStackSOF();try{javaStackSOF.stackLeak();}catch (Throwable e) {System.out.println("stacklength="+javaStackSOF.stackLength);throw e;}}}
运行结果:
stacklength=996//栈的深度Exception in thread "main" java.lang.StackOverflowError at JavaStackSOF.stackLeak(JavaStackSOF.java:9) at JavaStackSOF.stackLeak(JavaStackSOF.java:12) at JavaStackSOF.stackLeak(JavaStackSOF.java:12) at JavaStackSOF.stackLeak(JavaStackSOF.java:12) at JavaStackSOF.stackLeak(JavaStackSOF.java:12)
方案三:增大栈的容量-Xss3m,局部变量与方案一一样。
运行结果:
stacklength=128252//栈的深度Exception in thread "main" java.lang.StackOverflowError at JavaStackSOF.stackLeak(JavaStackSOF.java:12) at JavaStackSOF.stackLeak(JavaStackSOF.java:12)
在Java虚拟机中描述了2种异常:
1、如果线程请求的栈深度(每个方法压入栈中时,会创建一个栈帧,栈帧中包含有局部变量,栈帧决定栈的深度)大于虚拟机所允许的最大深度,将抛出StackOverflowError。
2、如果线程在扩展栈时无法申请到足够的空间,会抛出outofmemoryError(栈一般可以动态扩展,扩展时由于内存太小了,无法申请到足够的空间)。
其实这两种情况存在重叠的情况,当栈空间无法分配的时候,不知道是内存不够了,还是已使用的空间已达到最大。
在上述的实验中,无法产生OutOfMemoryError结果,一直都是StackOverflowError异常,并且局部变量越多,栈的深度越小。一般情况下,虚拟机默认参数,栈的深度是1000~2000,对于一般的方法调用足够了。
有一种情况会导致栈OOM
public class JavaStackOOM {private void dontStop(){while(true){}}public void stackLeakByThead(){while(true){Thread thread = new Thread(new Runnable() {public void run() {dontStop();}});thread.start();}}public static void main(String[] args) {JavaStackOOM javaStackOOM = new JavaStackOOM();javaStackOOM.stackLeakByThead();}}
上面这段代码虽然会导致OOM,但是这个跟栈空间是否充足没有关系,这个是由于栈是线程私有的,不断的用新线程去访问一个方法,会导致内存的不足,并且栈分配的内存越大越容易出现。在运行这段代码需要注意,无限产生线程很容易导致电脑卡死。
在建立过多的线程导致的OOM,在不减少线程的数量或者跟换64位虚拟机的情况下,只能通过减小最大堆,减少栈容量来换取更多的线程。
Java栈能分配的内存大小=系统限制的内存大小(如32位系统为2G) - Xmx(最大堆)-MaxPermSize(最大方法区),程序计数器消耗内存很小忽略,如果虚拟机进程本身耗费的内存不算在内,剩下的就由虚拟机栈和本地方法区瓜分了。
三、方法区和运行时常量池溢出
运行常量池溢出:参数:-XX:PermSize=10M -XXMaxPermSize=10M
在1.6之前(包括1.6)方法区采用永久代的实现方式来进行管理,导致方法区如果数据过多会导致OOM异常,在1.7之后逐步去永久代。
public static void main(String[] args) {List<String> list = new ArrayList<String>();int i= 0;while(true){ list.add(String.valueOf(i++).intern());//intern:检查常量池中是否有该字段,没有则复制该字段到常量池中。}}实验结果:
在1.6、1.7环境下分别执行都未能发生OOM异常,程序一直在执行,cpu占用90%以上。理论上,在JDK1.6环境下,会出现OOM异常,在1.7环境中会一直运行下去。
延伸1:
String str1 = new StringBuilder("计算机").append("软件").toString();System.out.println(str1.intern() == str1);String str2 = new StringBuilder("ja").append("va").toString();System.out.println(str2.intern() == str2);实验结果:
在JDK1.6环境下,结果是false,false,而在JDK1.7中,结果是:true,false
分析:JDK1.6,intern会把首次遇到的字符串复制到常量池中(永久代)去,返回的是常量池中的引用地址,而stringbuilder 创建的对象在堆中,所以引用显然是不同的。
而在JDK1.7中,则不会复制对象到常量池中,只会把堆中的地址记录到常量池中,而对于java字符串比较的结果为false,是因为在创建"计算机软件"之前,字符串常量池中已经有了"Java"的引用了。
延伸2:
public void test2(){String str1 = new StringBuilder("计算机").append("软件").toString();String str2 = "计算机软件";String str3 = "计算机软件";System.out.println(str1 == str2);System.out.println(str1.equals(str2));System.out.println(str3 == str2);}
实验结果:false true true
java代码在编译阶段,会在类文件的常量池中存放"计算机","软件","计算机软件"这几个字符,并且相同的字符只有一份,然后在JVM加载阶段,类文件中的常量池(也叫静态常量池)会加载到方法区的运行时常量池。然后在代码运行时执行new操作,如果常量池没有该字符或者字符引用,会在常量池中存储该字符或者字符引用,
显然str1 与str2的引用地址是不相等的,但是它们的内容是相等的,都是"计算机软件",str2与str3都是指向同一个对象,所以引用也是相等的。
方法区溢出:
方法区是存放Class的相关信息,如类名,常量池,字段描述,方法描述等。可以通过不停的加载类来实现方法区的溢出。由于操作太麻烦,没有验证。
- 模拟JVM内存溢出
- jvm 之 内存溢出场景模拟
- JVM 深入笔记(2)内存溢出场景模拟
- JVM 深入笔记(2)内存溢出场景模拟
- JVM 深入笔记(2)内存溢出场景模拟
- JVM内存溢出分析
- jvm内存溢出
- JVM内存溢出监控
- jvm内存溢出分析
- jvm内存溢出解决方案
- JVM内存溢出
- JVM 内存溢出
- myeclipse-----jvm内存溢出
- jvm内存溢出
- jvm内存溢出问题解决
- JVM虚拟机内存溢出
- JVM:内存溢出问题
- Java JVM:内存溢出
- SIFT,SURF,ORB,FAST 特征提取算法比较
- LeetCode——104. Maximum Depth of Binary Tree
- 【CUGBACM15级BC第31场 B】hdu 5179 beautiful number
- 简历制作
- 提出一种数据结构支持push和pop操作以及第三种操作findMin,返回最小值,所有操作均以O(1)最坏时间运行
- 模拟JVM内存溢出
- eclipse项目导入GitHub
- spring学笔记七
- HTTP Status 500
- js-格式化当前日期
- leetcode之subset II
- Java中的length和length()深入分析
- 2017-09-05
- 最小生成树Prim算法模板