首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

java虚拟机学习札记1-jvm的逻辑内存分配

2012-11-03 
java虚拟机学习笔记1-jvm的逻辑内存分配java虚拟机学习笔记1-jvm的逻辑内存分配声明博客内所有“java虚拟机

java虚拟机学习笔记1-jvm的逻辑内存分配

java虚拟机学习笔记1-jvm的逻辑内存分配

声明

博客内所有“java虚拟机学习笔记”系列的文章,均出自《深入理解java虚拟机-JVM高级特性与最佳实践-周志明》

?

java虚拟机在执行java程序的过程中把他所管理的内存划分成不同的逻辑数据区域,这些区域各有用途,特点不同,以下是根据《java虚拟机规范(第3版)》中规定的jvm运行时数据区域


java虚拟机学习札记1-jvm的逻辑内存分配

?

对于以上各个区域的详细说明,参见附件中的?Java虚拟机规范(Java_SE_7).pdf?

?

下面,进入实战OutOfMemoryError异常

?

1.java堆溢出

?

首先限制java堆的大小为20MB,不可扩展(将Xms,Xmx 的值设置为相同),通过

设置 -XX:+HeapDumpOnOutOfMemoryError 可以使JVM在内存溢出时Dump出内存转储快照以便事后分析

?

?

package org.star_java.jvm.memory;import java.util.ArrayList;import java.util.List;/** * VM Args -verbose:gc -Xms20m -Xmx20m -Xmn10m -XX:+HeapDumpOnOutOfMemoryError -XX:+PrintGCDetails -XX:SurvivorRatio=8 */public class HeapOOM{static class OOMObject{public static void main(String[] args){List<OOMObject> list = new ArrayList<OOMObject>();while (true){list.add(new OOMObject());}}}}
?

?

运行结果:

?

java.lang.OutOfMemoryError: Java heap space

Dumping heap to java_pid1068.hprof ...

Heap dump file created [27834496 bytes in 0.186 secs]

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

at java.util.Arrays.copyOf(Unknown Source)

at java.util.Arrays.copyOf(Unknown Source)

at java.util.ArrayList.grow(Unknown Source)

at java.util.ArrayList.ensureCapacityInternal(Unknown Source)

at java.util.ArrayList.add(Unknown Source)

at org.star_java.jvm.memory.HeapOOM$OOMObject.main(HeapOOM.java:18)

?

我们可以使用一些工具查看生成的内存转储快照,以下是使用 jvisualvm 查看的结果


java虚拟机学习札记1-jvm的逻辑内存分配

可以清晰的看出我们自己定义的类OOMObject造成了此次溢出

?

2.虚拟机栈和本地方法栈溢出

?

在HotSpot虚拟机中不区分虚拟机栈和本地方法栈,所以设置-Xoss(设置本地方法栈大小)是无效的,所以这里使用-Xss(栈容量)参数,关于本例,抛出2个异常:

1.如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverFlowError

2.如果虚拟机在扩展栈的深度时无法请求道足够的内存空间,则抛出OutOfMemoryError

?

?

package org.star_java.jvm.memory;/** *  VM Args -Xss128k */public class JavaVmStackSOF{private int stackLength = 1;private void stackLeak(){stackLength++;stackLeak();}public static void main(String[] args){JavaVmStackSOF oom = new JavaVmStackSOF();try{oom.stackLeak();}catch (Exception e){System.out.println("stack length : " + oom.stackLength);throw e;}}}
?

运行结果:

stack length : 2242

?

Exception in thread "main" java.lang.StackOverflowError

at org.star_java.jvm.memory.JavaVmStackSOF.stackLeak(JavaVmStackSOF.java:12)

at org.star_java.jvm.memory.JavaVmStackSOF.stackLeak(JavaVmStackSOF.java:13)

at org.star_java.jvm.memory.JavaVmStackSOF.stackLeak(JavaVmStackSOF.java:13)

...................................................................................................................................

...................................................................................................................................

at org.star_java.jvm.memory.JavaVmStackSOF.main(JavaVmStackSOF.java:21)

?

3.方法区溢出

?

方法去用于存放Class的相关信息,本例的基本思路是在运行时产生大量的类去填满方法区,直到溢出。

可以利用java的反射模拟本例,但是此处使用原作者的代码,使用开源项目CGLib直接操作字节码。

?

?

package org.star_java.jvm.memory;import java.lang.reflect.Method;import net.sf.cglib.proxy.Enhancer;import net.sf.cglib.proxy.MethodInterceptor;import net.sf.cglib.proxy.MethodProxy;/** * VM Args -XX:PermSize=10m -XX:MaxPermSize=10m -XX:+HeapDumpOnOutOfMemoryError */public class JavaMethodAreaOOM{static class OOMObject{}public static void main(String[] args){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();}}}

?

?

运行结果:

?

?

java.lang.OutOfMemoryError: PermGen space

Dumping heap to java_pid8464.hprof ...

Exception in thread "main" Heap dump file created [3855706 bytes in 0.308 secs]

?

Exception: java.lang.OutOfMemoryError thrown from the UncaughtExceptionHandler in thread "main"

?

?

我们可以使用一些工具查看生成的内存转储快照,以下是使用 jvisualvm 查看的结果

?


java虚拟机学习札记1-jvm的逻辑内存分配

?

可以看出, 我们使用CGLib创建了很多的类,造成了溢出

?

注:本例并非是一个纯粹的实验环境,当前的很多主流框架,如spring,hibernate,都会使用到CGLib这类字节码技术,这就需要方法区保证足够大来装载这些动态生成的Class,如在使用了CGLib技术的地方,大量JSP或动态生成大量jsp文件,给予OSGI 的应用等清况,都需要注意方法区的溢出

?

?

4.本机直接内存溢出

?

DirectMemory的容量可以通过 -XX:MaxDirectMemorySize指定,如果不指定,则默认与java堆的大小一样(-Xmx)。此处,我们使用原作者的代码,使用Unsafe类直接申请本地内存

?

?

package org.star_java.jvm.memory;import java.lang.reflect.Field;import sun.misc.Unsafe;/** * VM Args -Xms20m -XX:MaxDirectMemorySize=10m  */public class DirectMemoryOOM{private static final int _1MB = 1024 * 1024;public static void main(String[] args) throws Exception{Field unsafeField = Unsafe.class.getDeclaredFields()[0];unsafeField.setAccessible(true);Unsafe unsafe = (Unsafe) unsafeField.get(null);while (true){unsafe.allocateMemory(_1MB);}}}
?

运行结果:

?

?

Exception in thread "main" java.lang.OutOfMemoryError

at sun.misc.Unsafe.allocateMemory(Native Method)

at org.star_java.jvm.memory.DirectMemoryOOM.main(DirectMemoryOOM.java:21)

?

====================================================================================================

?

以上是JVM对内存的解释,划分以及使用。主要代码演示了使JVM内存溢出的方法,

在自己的编程也要多加注意,多增加一些调试此类异常的经验

?

?

热点排行