初探JVM内存区域

[size=large][b]1 JVM架构[/b][/size]
[img]http://dl.iteye.com/upload/attachment/547185/0ddc0fbb-2bcb-3106-9997-ed5879445ecb.gif[/img]
线程私有内存:程序计数器,Java虚拟机栈,本地方法栈
线程共享内存:Java堆,方法区
[quote][b]程序计数器(Program Counter Register)[/b]:当前线程所执行的字节码的行号指示器。如果线程执行的是一个java方法,这个计算器记录的是正在持行的虚拟机字节码指令的地址;如果执行的是Native方法,这个计数器则为空。此区域是java虚拟器规范中唯一没有定义任何OutOfMemoryError情况的区域[/quote]
[quote][b]Java虚拟机栈:[/b]它是描述java方法执行的内存模型:每个方法被执行的时候都会创建一个stack frame用于储存局部变量表,操作栈,动态链接,方法出口等信息。每一个方法被调用至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈道出栈的过程。
如果线程所请求的栈深度大于虚拟机所永许的深度,将抛出StackOverflowError,如果虚拟机栈可以动态扩展,当扩展时无法申请足够的内存时会抛出OutOfMemoryError。[/quote]
[quote][b]本地方法栈:[/b]与java虚拟机栈作用类似,不过他是位执行Native方法服务。本地方法栈区域也会抛出StackOverflowError和OutOfMemoryError[/quote]
[quote][b]Java堆:[/b] 它是虚拟机管理的内存中最大的一块。它是被所有线程共享的一块区域,是虚拟机创建的。它是存放对象实例,几乎所有对象实例都在堆上分配。它是垃圾回收器管理的主要区域。可以进一步分为Eden空间,from survivor控件爱你,to survivor空间等,可以通过-Xmx 和 -Xms 控制堆的大小,当缺少内存时出现OutOfMemoryError[/quote]
[quote][b]方法区:[/b]它和java堆一样,是各个线程共享的内存区域,它用于存储以被虚拟器加载的类信息/常量/静态变量/即时编译器编译后的代码等数据。如果它无法满足内存分配,将抛出OutOfMemoryError异常。

[b]运行时常量池:[/b]它是方法区的一部分,Class文件中除啦有类的版本,字段,方法,接口等描述性信息外,还有一个是常量池(Constant Pool Table),用于存放编译器生成的各种字面量和符号引用,这部分内容会在类加载后存放到方法去的运行时常量池中。当缺少内存时出现OutOfMemoryError[/quote]

[size=large][b]
2 基于sun jvm 实战OutOfMemoryError异常情况和分析过程
[/b][/size]
[size=medium][b]堆内存错误分析[/b][/size]
import java.util.ArrayList;
import java.util.List;

/**
*VM Arguments: -verbose:gc -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError
*/
public class HeapOOM {
static class OOMObject{}
public static void main(String[] args) {
List list = new ArrayList();
while(true) {
list.add(new OOMObject());
}
}

}


[b]添加eclipse运行参数 -verbose:gc -Xms20m -Xmx20m[/b]
[img]http://dl.iteye.com/upload/attachment/547922/b31f0259-b81e-3e46-96c9-0b3922cd8375.gif[/img]

[b]参数含义[/b]
[table]
|-verbose:gc|显示gc过程
|-Xms|堆的最小动态内存
|-Xmx|堆的最大动态内存
|-XX:+HeapDumpOnOutOfMemoryError|dump堆快照
[/table]

[b]运行结果:[/b]
[img]http://dl.iteye.com/upload/attachment/547927/fc565d1f-2ce7-3556-b09b-aaaa316f3c4b.gif[/img]
[quote]可以使用eclipse memory analyzer这个Jvm堆分析内存泄漏或者溢出的原因.
eclipse memory analyzer update url:[url]http://download.eclipse.org/mat/1.1/update-site/[/url]

如果内存泄漏可以看卡泄漏对象到GC Roots的引用链,从而分析出泄漏的代码位置。我们可从下图看出OOMObject占用大量堆空间。

如果是内存溢出,那就是说内存中的对象都应该存在着,那就检查虚拟机参数-Xmx与-Xms是否可以变大。[/quote]

[b]eclipse memory analyzer dominator tree 视图[/b]
[img]http://dl.iteye.com/upload/attachment/547938/ce3e39e4-bd92-308c-8e30-cdfc8ad5dc3d.gif[/img]

[table]
|Shallow heap|对象自身占用的heap空间,不包括它引用的对象
|Retained heap|前对象+当前对象可直接或间接引用到的对象总体所占用的空间
[/table]

[b]
其他与jvm内存空间相关参数[/b]
[table]
|-Xss|设置虚拟机栈和本地方法栈的大小
|-XX:PermSize|方法区最小空间
|-XX:MaxPermSize|方法区最大空间
[/table]


[b]栈溢出[/b]
public class JavaVMStackOOM
{

private int stackLength = 1;

public void stackLeak()
{
stackLength++;
stackLeak();
}

/**
* vm args -Xss128k
*/
public static void main(String[] args)
{
JavaVMStackOOM stackOOM = new JavaVMStackOOM();
stackOOM.stackLeak();
}

}



[b]运行时常量池溢出[/b]
public class ConstantsPoolOOM
{

/**
* VM Args: -XX:PermSize=10M -XX:MaxPermSize=10M
*/
public static void main(String[] args)
{
List list = new ArrayList();
int i = 0;
while (true)
{
list.add(String.valueOf(i++).intern());
}
}

}



[b]方法区异常[/b]
public class MethodAreaOOM
{

/**
* VM Args: -XX:PermSize=10M -XX:MaxPermSize=10M
*/
public static void main(String[] args)
{
while (true)
{
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(OOMObject.class);
enhancer.setUseCache(false);
enhancer.setCallback(new MethodInterceptor()
{

@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy)
throws Throwable
{
return proxy.invokeSuper(obj, args);
}
});
enhancer.create();
}
}

static class OOMObject
{

}
}


[b]本机直接内存溢出[/b]
public class DirectMemoryOOM
{

private static final int _1MB = 1024 * 1024;

/**
* VM Args: -Xmx20M -XX:MaxDirectMemorySize=10M
*
* @throws IllegalAccessException
* @throws IllegalArgumentException
*/
public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException
{
Field unsafeFiled = Unsafe.class.getDeclaredFields()[0];
unsafeFiled.setAccessible(true);
Unsafe unsafe = (Unsafe) unsafeFiled.get(null);
while (true)
{
unsafe.allocateMemory(_1MB);
}
}

}

你可能感兴趣的:(J2EE/JVM)