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
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
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
for (int i = 0;; i++) {
long l = unsafe.allocateMemory(_1MB);
list.add(l);
System.out.println(i);
}
}
static void byteBufferAllocate(boolean direct) {
List
for (int i = 0;; i++) {
ByteBuffer bb;
if (direct) {
bb = ByteBuffer.allocateDirect(_1MB);
} else {
bb = ByteBuffer.alloc