JVM 深入笔记(2)内存溢出场景模拟
来源:互联网 发布:mac魔兽世界 编辑:程序博客网 时间:2024/06/06 02:28
- 作者:柳大 · Poechant
- 电邮:zhongchao.ustc#gmail.com (#->@)
- 博客:blog.csdn.net/poechant
- 日期:Feb. 23st 2012
《JVM 深入笔记(1)内存区域是如何划分的?》一文已经介绍了 JVM 对内存区域的划分与管理。在现实的编程过程中,会遇到一些 OutOfMemoryError (OOM) 的情形。通过模拟,我们可以直接点中这些场景的本质,从而在纷繁复杂的千万行代码中避免这样去 coding。导致 OOM 的情况有多种,包括 Java 或 Native Method Stack 的内存不足或者栈空间溢出、Heap 内存溢出、Non-heap 内存溢出、Direct Memory 溢出。
参考:《深入理解Java虚拟机》
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 -Xss128Kpackage 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: 1052Exception in thread "main" java.lang.StackOverflowError at com.sinosuperman.main.Test.stackOverflow(Test.java:8) at com.sinosuperman.main.Test.stackOverflow(Test.java:9) at com.sinosuperman.main.Test.stackOverflow(Test.java:9) at com.sinosuperman.main.Test.stackOverflow(Test.java:9) 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 -Xms50mpackage 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 moreCaused 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 的内存溢出问题本质上大都可归结为以上这几种情况。
- JVM 深入笔记(2)内存溢出场景模拟
- JVM 深入笔记(2)内存溢出场景模拟
- JVM 深入笔记(2)内存溢出场景模拟
- JVM 深入笔记(2)各内存区溢出场景模拟
- jvm 之 内存溢出场景模拟
- 模拟JVM内存溢出
- 【深入理解JVM】第2章 JVM内存分布与溢出 笔记
- 笔记:深入理解JVM 第2章 Java内存区域与内存溢出
- 深入理解JVM虚拟机学习笔记(—)内存区域与内存溢出异常
- 深入理解JVM(2)——内存区域与内存溢出
- 各内存区溢出场景模拟
- JVM学习笔记-内存溢出
- JVM学习笔记-内存溢出
- 深入理解JVM笔记一-java内存区域与内存溢出异常
- 深入理解Java虚拟机笔记--JVM内存模型及溢出问题总结
- JVM内存溢出有什么优化、具体使用场景
- 深入JVM(之一)--Java内存区域与内存溢出异常
- 深入理解JVM之内存区域与内存溢出
- Android InflateLayout.inflate()原理分析
- Linux负载均衡软件LVS之一(概念篇)
- 公开课机器学习笔记(15)支持向量机五 坐标上升法 SMO优化算法
- 图说浏览器的缓存原理及缓存方式说明(1)
- 解决U盘中文件全部变成快捷方式的问题
- JVM 深入笔记(2)内存溢出场景模拟
- hdu 1011 Starship Troopers (树形dp+背包)
- Genero Studio如何改变界面字段输入顺序
- 第一章第十题
- cmd下不能ipconfig的解决方法
- 机房重构有感
- 第一章第十一题
- Android 深入解析AsyncTask(doInBackground不工作)
- hdu-1283-最简单的计算机