面试知识库
极高 基础

JVM内存结构#

一句话答案#

JVM 内存分堆(新生代/老年代)、方法区(元空间)、虚拟机栈、本地方法栈、程序计数器,其中堆和方法区线程共享。

核心要点

JVM 运行时数据区(JDK 8):

各区域详解:

1. 堆(Heap)—— 最大的一块,GC 主战场

  • 存放:所有对象实例、数组(new 出来的东西都在这)
  • 线程共享,GC 主要回收此区域
  • 划分:年轻代(Eden + S0 + S1) + 老年代

2. 方法区(Method Area)—— JDK 8 改为 Metaspace

  • 存放:类的元信息(字段、方法、接口描述)、运行时常量池、静态变量、JIT 编译后的代码缓存
  • JDK 7 之前叫永久代(PermGen,堆内),JDK 8 改为 Metaspace(本地内存,不受 -Xmx 限制)
  • String.intern() 的字符串字面量从 JDK 7 起移入堆中

3. 虚拟机栈(VM Stack)

  • 每个线程私有,随线程创建
  • 由栈帧(Stack Frame)组成,每调用一个方法压入一个栈帧
  • 栈帧包含:局部变量表、操作数栈、动态链接、方法返回地址

4. 本地方法栈(Native Method Stack)

  • 专门服务 native 方法(JNI)
  • HotSpot 将虚拟机栈和本地方法栈合并为一个

5. 程序计数器(Program Counter Register)

  • 最小的一块内存,记录当前线程执行的字节码指令地址
  • 唯一一个不会 OOM 的区域
  • 线程切换后用于恢复执行位置
面试回答(2分钟版)

JVM 运行时数据区分为五个部分,其中堆和方法区是线程共享的,虚拟机栈、本地方法栈和程序计数器是线程私有的。堆是最大的一块内存,所有 new 出来的对象实例和数组都在堆上分配,也是 GC 的主战场,内部划分为年轻代(Eden、S0、S1)和老年代。方法区存储类的元信息、运行时常量池、静态变量和 JIT 编译后的代码缓存,JDK8 之前叫永久代在堆内,JDK8 之后改为 Metaspace 使用本地内存,不受 -Xmx 限制。虚拟机栈每个线程一个,每调用一个方法就压入一个栈帧,栈帧包含局部变量表、操作数栈、动态链接和方法返回地址,递归过深会抛 StackOverflowError。本地方法栈服务于 JNI 的 native 方法,HotSpot 中和虚拟机栈合二为一。程序计数器记录当前线程执行的字节码行号,用于线程切换后恢复执行位置,是唯一不会发生 OOM 的区域。

追问与易错

追问方向:

  • “方法区和元空间什么关系?”→ JDK8 用元空间实现方法区,存在本地内存而非堆中
  • “虚拟机栈中存什么?”→ 栈帧:局部变量表/操作数栈/动态链接/方法返回地址
  • “哪些区域会 OOM?”→ 堆/元空间/栈/直接内存都可能

易错点:

  • ❌ “JDK8 没有方法区了”——方法区是规范概念仍存在,只是实现从永久代改为元空间
  • ❌ “栈不会溢出”——递归过深会 StackOverflowError