JVM运行时内存空间结构 (一)

2014-11-24 11:01:05 · 作者: · 浏览: 0

JVM执行Java程序的过程中管理的内存空间,包括下列几个区域:

程序计数器(Program CounterRegister)


· 线程私有,占用空间很小。


· 线程所执行代码行号指示器。


· 解释器通过计数器的值选择下一条执行的字节码指令。


· 线程执行Native方法时值为空。


· 没有OOM(OutOfMemory)。Java虚拟机栈(Java Virtual Machine Stacks)


· 线程私有。· 储存方法栈帧(Stack Frame)。


· 栈帧:储存局部变量表、操作栈、动态链接、方法出口等。


· 局部变量表:编译器可知的基本类型、对象引用和returnAddress(字节码指令的地址)。在编译期间完成分配,运行时大小不变。


· 存在StackOverflowError和OOM。


· StackOverflowError:线程请求栈深度大于VM允许深度。


· OOM:创建线程或扩展线程空间时无足够内存。

StackOverflowError例子:


/**
* -Xss256k
*
* @author Alfred Xu
*
*/
public class StackSOF {
int recursionLength;
void recusion() {
recursionLength++;
recusion();
}
public static void main(String[] args) {
StackSOF sof = new StackSOF();
try {
sof.recusion();
} catch (Throwable e) {
System.out.println(sof.recursionLength);
e.printStackTrace();
}
}
}

OOM例子:


/**
* -Xss2m
*
* @author Alfred Xu
*
*/
public class StackOOM {
static class Tester extends Thread {
@Override
public void run() {
try {
Thread.sleep(1000 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
for (int i = 0;; i++) {
new Tester().start();
System.out.println(i);
}
}
}


本地方法栈(Native MethodStacks)


· 线程私有,类似虚拟机栈。


· 服务Native方法。


· 同样存在StackOverflowError和OOM。


· Hotspot中将Java虚拟机栈和本地方法栈合二为一,通过-Xss设置大小。JDK1.6以前默认256K,1.6默认1M。


Java堆(Java Heap)


· 所有线程共享。


· 储存对象实例。


· GC和OOM的主要区域。


Heap OOM例子:


/**
* -Xms10m -Xmx10m
*
* @author Alfred Xu
*
*/
public class HeapOOM {
public static void main(String[] args) {
List list = new ArrayList();
for (long i = 0;; i++) {
list.add(i);
System.out.println(i);
}
}
}


方法区(Method Area)


· 又叫非堆(Non-Heap),对应HotSpot的永久代(Permanent Generation)。


· 所有线程共享。


· 储存VM加载的类信息、常量、静态变量、JIT编译代码等。


· 也有OOM,一般是由于大量使用反射生成class。


· 包含运行时常量池(Rumtime ConstantPool)。


常量池溢出例子:


/**
* -XX:MaxPermSize=1m
*
* @author Alfred Xu
*
*/
public class ConstantPoolOOM {
public static void main(String[] args) {
List list = new ArrayList();
for (int i = 0;; i++) {
list.add(String.valueOf(i).intern());
System.out.println(i);
}
}
}


本机直接内存(Direct Memory)


· 不受VM直接管理,但也有OOM。


· 和NIO中的DirectByteBuffer相关。


· 默认和Java堆大小一致。


例子:


/**
* -XX:MaxDirectMemorySize=10m
*
* @author Alfred Xu
*
*/
@SuppressWarnings("restriction")
public class DirectMemoryOOM {
static final int _1MB = 1024 * 1024;
static void unsafeAllocate() throws IllegalArgumentException,
IllegalAccessException {
Field unsafeField = Unsafe.class.getDeclaredFields()[0];
unsafeField.setAccessible(true);
Unsafe unsafe = (Unsafe) unsafeField.get(null);
List list = new ArrayList();
for (int i = 0;; i++) {
long l = unsafe.allocateMemory(_1MB);
list.add(l);
System.out.println(i);
}
}
static void byteBufferAllocate(boolean direct) {
List list = new ArrayList();
for (int i = 0;; i++) {
ByteBuffer bb;
if (direct) {
bb = ByteBuffer.allocateDirect(_1MB);
} else {
bb = ByteBuffer.alloc