JVM内存区域

234 阅读4分钟


image.png

线程独占区

程序计数器(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参数:
    • -Xss(设置栈容量)
  • 异常
    • StackOverFlowError(线程请求的栈深度大于虚拟机所允许的最大深度)
/**
 * 使用-Xss参数减少栈内存容量
 * VM Args: -Xss128k
 */
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;
        }
    }
}

// 运行结果:
// stack length:2402
// Exception in thread "main" java.lang.StackOverflowError
/**
 * 定义了大量的本地变量,增大此方法帧中本地变量表的长度。
 */
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;
        }
    }
}

// 运行结果:
// stack length:5675
// Exception in thread "main" java.lang.StackOverflowError
  • OutOfMemoryError(当扩展栈容量无法申请到足够的内存时,HotSpot不支持扩展,所以除非在创建线程申请内存时就无法获得足够的内存)
/**
 * 创建线程导致内存溢出异常
 * VM Args: -Xss2M
 */
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();
    }
}

// 运行结果:
// Exception in thread "main" java.lang.OutOfMemoryError: unable to create native thread,
// possibly out of memory or process/resource limitsreached

本地方法栈(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):直接增加堆内存大小(检查是否存在某些对象生命周期过长、持有状态时间过长、存储结构设计不合理)
/**
 * VM Args: -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError
 */
public class HeapOOM {
	static class OOMObject {
    }
    
    public static void main(String[] args) {
    	List<OOMOjbect> list = new ArrayList<OOMObject>();
        
        while (true) {
        	list.add(new OOMObject());
        }
    }
}

// 运行结果:
//java.lang.OutOfMemoryError: Java heap space

方法区(Method Area)

  • 存储虚拟机加载的类信息、常量、静态常量、即时编译器编译后的代码等数据
    • 类信息:版本、字段、方法、接口
  • 运行时常量池(Runtime Constant Pool)
    • 常量池表(Constant Pool Table):存放编译期生成的各种字面量与符号引用。
    • String::intern():如果字符串常量池中已经包含了一个等于此String对象的字符串,则返回代表池中这个字符串的String对象的引用;否则,会将此String对象包含的字符串添加到常量池中,并且返回此String对象的引用。
  • 垃圾回收在方法区的行为
    • 常量池的回收
    • 类的卸载
  • VM参数
    • -XX : MaxMetaspaceSize(设置元空间最大值)
    • -XX : MetesapceSize(指定元空间的初始空间大小)
    • -XX : MinMeetaspaceFreeRatio(在垃圾收集之后控制最小的元空间剩余容量的百分比,可减少因为元空间不足导致的垃圾收集的频率)
    • -XX : MaxMeetaspaceFreeRatio(在垃圾收集之后控制最大的元空间剩余容量的百分比)
  • 异常
    • OutOfMemoryError