线程独占区
程序计数器(Program Counter Register)
- 程序计数器是一块较小的内存空间,它可以看做是当前线程所执行的字节码的行号指示器。
- 如果线程执行的是Java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址。如果正在执行的是native方法,这个计数器的值为undefined。
- 此区域是唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域。
Java虚拟机栈(Java Virtual Machine Stack)
- 虚拟机栈描述的是Java方法执行的动态内存模型,与线程的声明周期一致。
- 栈帧(Stack Frame)
- 每个方法执行,都会创建一个栈帧,伴随着方法从创建到执行完成,用于存储局部变量表,操作数栈,动态链接,方法出口等。
- 每个方法被调用直至执行完毕的过程,就是一个栈帧在虚拟机栈中从入栈到出栈的过程。
- 局部变量表
- 存放编译期可知的各种基本数据类型(boolean、byte、char、short、int、float、long、double),对象引用(reference类型),returnAddress类型(指向了一条字节码指令的地址)
- 这些数据类型在局部变量表中的存储空间已局部变量槽(Slot,32bit)来表示。
- 所需的内存空间在编译期完成分配。当进入一个方法是,这个方法需要在栈帧分配多少内存时固定的,在方法运行期间是不会改变局部变量表的大小
- JVM参数:
- 异常
- StackOverFlowError(线程请求的栈深度大于虚拟机所允许的最大深度)
public class JavaVMStackSOF {
private int stackLength = 1;
public void stackLeak() {
stackLength++;
stackLeak();
}
public static void main(String[] args) throws Throwable {
JavaVMStackSOF oom = new JavaVMStackSOF();
try {
oom.stackLeak();
} catch (Throwable e) {
System.out.println("stack length:" + oom.stackLength);
throw e;
}
}
}
public class JavaVMStackSOF {
private static int stackLength = 0;
public static void test() {
long unused1, unused2, unused3, unused4, ....;
stackLength++;
test();
unused1 = unused2 = unused3 = unused4 = ... = 0;
}
public static void main(String[] args) {
try {
test();
} catch (Error e) {
System.out.println("stack length:" + stackLength);
throw e;
}
}
}
- OutOfMemoryError(当扩展栈容量无法申请到足够的内存时,HotSpot不支持扩展,所以除非在创建线程申请内存时就无法获得足够的内存)
public class JavaVMStackOOM {
private void dontStop() {
while (true) {
}
}
public void stackLeakByThread() {
while (true) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
dontStop();
}
});
thread.start();
}
}
public static void main(String[] args) throws Throwable {
JavaVMStackOOM oom = new JavaVMStackOOM();
oom.stackLeakByThread();
}
}
本地方法栈(Native Method Stack)
- 为虚拟机使用到的本地(Native)方法服务
- 异常
- StackOverFlowError
- OutOfMemoryError
线程共享区
堆(Heap)
- 存放对象实例(逃逸分析技术:栈上分配、标量替换)
- 划分多个线程私有的分配缓冲区(Thread Local Allocation Buffer,TLAB)。
- 目的:更好地回收内存,更快地分配内存。
- -XX:+/-UseTLAB 是否使用TLAB。
- JVM参数
- -Xmx(设置最大堆大小)
- -Xms(设置初始堆大小)
- -XX : +HeapDumpOnOutOfMemoryError(内存溢出时Dump出当前的内存堆转储快照)
- 异常
- OutOfMemoryError
- 内存泄漏(Memory Leak):查看泄漏对象到GC Roots的引用链,找到泄漏对象是怎样的引用路径、与哪些GC Roots相关联
- 内存溢出(Memory Overflow):直接增加堆内存大小(检查是否存在某些对象生命周期过长、持有状态时间过长、存储结构设计不合理)
public class HeapOOM {
static class OOMObject {
}
public static void main(String[] args) {
List<OOMOjbect> list = new ArrayList<OOMObject>();
while (true) {
list.add(new OOMObject());
}
}
}
方法区(Method Area)
- 存储虚拟机加载的类信息、常量、静态常量、即时编译器编译后的代码等数据
- 运行时常量池(Runtime Constant Pool)
- 常量池表(Constant Pool Table):存放编译期生成的各种字面量与符号引用。
- String::intern():如果字符串常量池中已经包含了一个等于此String对象的字符串,则返回代表池中这个字符串的String对象的引用;否则,会将此String对象包含的字符串添加到常量池中,并且返回此String对象的引用。
- 垃圾回收在方法区的行为
- VM参数
- -XX : MaxMetaspaceSize(设置元空间最大值)
- -XX : MetesapceSize(指定元空间的初始空间大小)
- -XX : MinMeetaspaceFreeRatio(在垃圾收集之后控制最小的元空间剩余容量的百分比,可减少因为元空间不足导致的垃圾收集的频率)
- -XX : MaxMeetaspaceFreeRatio(在垃圾收集之后控制最大的元空间剩余容量的百分比)
- 异常