Java 虚拟机(JVM)内存模型是 Java 面试中的高频考点。理解 JVM 内存模型对于优化 Java 应用性能、排查内存溢出(OOM)问题至关重要。
运行时数据区域
Java 虚拟机在执行 Java 程序的过程中会把它所管理的内存划分为若干个不同的数据区域。根据《Java 虚拟机规范》,这些区域可以分为以下几类:
1. 程序计数器 (Program Counter Register)
这是一块较小的内存空间,可以看作是当前线程所执行的字节码的行号指示器。它是线程私有的,生命周期与线程相同。如果线程执行的是 Java 方法,计数器记录的是正在执行的虚拟机字节码指令的地址;如果执行的是 Native 方法,计数器值为空(Undefined)。
2. Java 虚拟机栈 (Java Virtual Machine Stack)
也是线程私有的。每个方法被执行的时候,Java 虚拟机都会同步创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态连接、方法出口等信息。每一个方法被调用直至执行完毕的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。
3. 本地方法栈 (Native Method Stack)
与虚拟机栈发挥的作用非常相似,区别是虚拟机栈为虚拟机执行 Java 方法服务,而本地方法栈则为虚拟机使用到的本地(Native)方法服务。
4. Java 堆 (Java Heap)
这是虚拟机所管理的内存中最大的一块。Java 堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。Java 堆是垃圾收集器管理的内存区域,因此也被称作“GC 堆”。
5. 方法区 (Method Area)
与 Java 堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。在 JDK 8 之前,HotSpot 虚拟机使用永久代(Permanent Generation)来实现方法区;JDK 8 开始,永久代被元空间(Metaspace)取代,元空间使用本地内存。
内存溢出异常
- StackOverflowError: 线程请求的栈深度大于虚拟机所允许的深度(例如无限递归)。
- OutOfMemoryError: Java 堆或方法区无法满足内存分配需求。
深入理解这些区域的作用和特性,能帮助我们更好地配置 JVM 参数(如 -Xmx, -Xms, -Xss),构建高可用、高性能的 Java 应用。

发表评论 取消回复