代码实现堆溢出、栈溢出、永久代溢出、直接内存溢出
- 栈溢出(StackOverflowError)
- 堆溢出(OutOfMemoryError:Java heap space)
- 永久代溢出(OutOfMemoryError: PermGen space)
- 直接内存溢出
一、堆溢出
创建对象时如果没有可以分配的堆内存,JVM就会抛出OutOfMemoryError:java heap space异常。
堆溢出实例:
/*** VM Args: -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError*/
public static void main(String[] args) {List<byte[]> list = new ArrayList<>();int i=0;while(true){list.add(new byte[5*1024*1024]);System.out.println("分配次数:"+(++i));}
}运行结果:
分配次数:1
分配次数:2
分配次数:3java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid2464.hprof ...
Heap dump file created [16991068 bytes in 0.047 secs]Exception in thread "main" java.lang.OutOfMemoryError: Java heap spaceat com.ghs.test.OOMTest.main(OOMTest.java:16)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
附:dump文件会在项目的根目录下生成
从上面的例子我们可以看出,在进行第4次内存分配时,发生了内存溢出。
二、栈溢出
栈空间不足时,需要分下面两种情况处理:
- 线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError
- 虚拟机在扩展栈深度时无法申请到足够的内存空间,将抛出OutOfMemberError
附:当前大部分的虚拟机栈都是可动态扩展的。
1、栈空间不足——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.StackOverflowErrorat 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
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
我们可以看到,sofMethod()方法递归调用了982次后,出现了StackOverflowError。
2、栈空间不足——OutOfMemberError实例
单线程情况下,不论是栈帧太大还是虚拟机栈容量太小,都会抛出StackOverflowError,导致单线程情境下模拟栈内存溢出不是很容易,不过通过不断的建立线程倒是可以产生内存溢出异常。
public class StackOOMTest {public static void main(String[] args) {StackOOMTest test = new StackOOMTest();test.oomMethod();}public void oomMethod(){while(true){new Thread(new Runnable() {@Overridepublic void run() {loopMethod();}}).start();;}}private void loopMethod(){while(true){}}
}运行结果:
……操作系统直接挂掉了
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
如果哪位大神能够成功模拟,还望指点一二。
三、永久代溢出
永久代溢出可以分为两种情况,第一种是常量池溢出,第二种是方法区溢出。
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<String> list = new ArrayList<>();int i=1;try {while(true){list.add(UUID.randomUUID().toString().intern());i++;}} finally {System.out.println("运行次数:"+i);}}
}运行结果:
……比较尴尬的是,通过intern,始终无法模拟出常量池溢出,我的猜想是JDK7对常量池做了优化。
如果哪位大神成功模拟出来了,还望指点一二。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
找了好久,终于弄清楚了使用string.intern()方法无法模拟常量池溢出的原因。
因为在JDK1.7中,当常量池中没有该字符串时,JDK7的intern()方法的实现不再是在常量池中创建与此String内容相同的字符串,而改为在常量池中记录Java Heap中首次出现的该字符串的引用,并返回该引用。
简单来说,就是对象实际存储在堆上面,所以,让上面的代码一直执行下去,最终会产生堆内存溢出。
下面我将堆内存设置为:-Xms5m -Xmx5m,执行上面的代码,运行结果如下:
运行次数:58162
Exception in thread "main" java.lang.OutOfMemoryError: Java heap spaceat 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)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
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() {@Overridepublic 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"
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
虽然出现了异常,但是打印的堆栈信息似乎并不是我们想要的……
四、直接内存溢出
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.OutOfMemoryErrorat sun.misc.Unsafe.allocateMemory(Native Method)at com.ghs.test.DirectMemoryOOMTest.main(DirectMemoryOOMTest.java:20)
分配次数:27953
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
总结:
栈内存溢出:程序所要求的栈深度过大。
堆内存溢出: 分清内存泄露还是 内存容量不足。泄露则看对象如何被 GC Root 引用,不足则通过调大-Xms,-Xmx参数。
永久代溢出:Class对象未被释放,Class对象占用信息过多,有过多的Class对象。
直接内存溢出:系统哪些地方会使用直接内存。
代码实现堆溢出、栈溢出、永久代溢出、直接内存溢出相关推荐
- java堆结构,以及堆中的永久代
转自:java堆的结构以及堆中的永久代 java堆不是数据结构意义上的堆(一种有序的树),而是jvm的堆,也即是运行时的数据区.所有类的实例和数组都是在堆上分配内存,它在JVM启动时被创建,对象所占的 ...
- 什么是内存溢出?在哪些区域会发生内存溢出?
什么是内存溢出?在哪些区域会发生内存溢出?回答这个问题,我们需要先看一看Java代码是怎么运行的.现在计入说我们写了一个 HelloWorld.class: 1 2 3 4 5 6 public cl ...
- 五种内存溢出案例总结:涵盖栈深度溢出、永久代内存溢出、本地方法栈溢出、JVM栈内存溢出和堆溢出
大家好,我是冰河~~ 相信小伙伴们在平时工作的过程中,或多或少都会遇到一个场景:内存溢出.如果你没有遇到过这个场景,那就说明你是个假的程序员.哈哈,开个玩笑,平时工作过程中,我们确实会遇到这个问题.今 ...
- java 堆中的永久代_JVM中的堆的新生代、老年代、永久代详解
JVM中的堆一般分为三大部分:新生代.老年代.永久代,其大致的占比如下: 一.新生代 新生代主要用来存放新生的对象.一般占据堆空间的1/3.在新生代中,保存着大量的刚刚创建的对象,但是大部分的对象都是 ...
- 马士兵—JVM—内存溢出—1.线上OOM(内存溢出)问题排查——亲测
1. 模拟线上oom问题 1.1 代码 @GetMapping("/addList")public void addList(){List list = new ArrayList ...
- 内存泄露和溢出的区别_Java 中的内存溢出和内存泄露是什么?我给你举个有味道的例子?...
JAVA中的内存溢出和内存泄露分别是什么,有什么联系和区别,让我们来看一看. 内存泄漏 & 内存溢出 1. 内存泄漏(memory leak ) 申请了内存用完了不释放,比如一共有 1024M ...
- ajax timeout 内存溢出,setInterval 和 setTimeout会产生内存溢出
setInterval 和 setTimeout会产生内存溢出 来一个简单的例子.有兴趣的朋友可以自己尝试 复制代码 代码如下: function a(){ document.title = &quo ...
- java模拟内存溢出并分析_本地模拟内存溢出并分析Dump文件
java Dump文件分析 前言 dump文件是java虚拟机内存在某一时间点的快照文件,一般是.hprof文件,下面自己模拟一下本地内存溢出,生成dump文件,然后通过mat工具分析的过程. 配置虚 ...
- java内存溢出怎么排查_java线上内存溢出问题排查步骤
一般线上遇到比较头疼的就是OOM内存溢出问题,我们都会先看错误日志,如果错误日志能够定位出哪个类对象导致内存溢出,那么我们只需要针对问题修改bug就好.但是很多时候我们单凭日志无法定位出内存溢出问题, ...
- linux weblogic 内存溢出,weblogic 安装升级补丁出现内存溢出问题解决
执行weblogic升级命令时,出现内存溢出问题: d:\Oracle\Middleware\utils\bsu>bsu.cmd -install -patch_download_dir=d:\ ...
最新文章
- c语言循环控制答案,C语言程序设计 实四 循环控制 答案 《西北民大 电气院》.doc...
- 模块化、层次化网络监控平台
- for(;;)函数中判断条件执行顺序
- mysql执行过程五步_简单五步教你搭建MySQL主从复制
- GARFIELD@01-19-2005
- java jdk 未知错误_解决JAVA JDK安装出错的最常见问题,帮你排除困扰
- python开发学习记录
- 设置Myeclipse中的代码格式化、及保存时自动格式化
- swift UI专项训练15 PcikerView老虎机视图
- 设置和开通freebsd远程登录
- php基本语法(简略篇)
- 2040: [蓝桥杯2022初赛] 砍竹子(优先队列)
- git分支的拉取和获取master分支最新代码
- Java录制网页_Java 录制语音的实现代码
- 服务网格领域的百花齐放
- python 文字识别 准确率_关于OCR图片文本检测、推荐一个 基于深度学习的Python 库!...
- 中国微商概念及产业链分析
- 如何彻底删除ELTIMA的vspd(虚拟串口)
- python水浒传名字次数_可视化分析《水浒传》各章回人名
- 网上报修 php源码,25175网上报修系统管理平台 v2.9