JVM 内存模型是理解 Java 程序运行的基础。
JVM 运行时数据区
┌─────────────────────────────┐
│ 方法区/元空间 │ ← 类信息、常量、静态变量
├─────────────────────────────┤
│ 堆 │ ← 对象实例、数组
├──────────┬──────────────────┤
│ 虚拟机栈 │ 本地方法栈 │ ← 方法调用、局部变量
├──────────┴──────────────────┤
│ 程序计数器 │ ← 当前线程执行位置
└─────────────────────────────┘
堆(Heap)
- 存放所有对象实例和数组
- 线程共享
- GC 的主要区域
- 分代:新生代(Eden + S0 + S1)+ 老年代
虚拟机栈(Stack)
- 每个线程一个栈
- 每个方法调用 = 一个栈帧
- 栈帧包含:局部变量表、操作数栈、动态链接、返回值
- StackOverflowError:栈深度超过限制(无限递归)
- OutOfMemoryError:栈内存耗尽
方法区 → 元空间
JDK 7 的方法区(永久代)在 JDK 8 被移除,改为元空间(Metaspace)。
元空间使用本地内存(不是堆内存),解决了永久代的 OOM 问题。但如果不限制大小(-XX:MaxMetaspaceSize),理论上也会耗尽本地内存。
字符串常量池
JDK 7 开始从方法区移到堆里。为什么?方法区 GC 触发条件苛刻,字符串常量在堆里更容易被回收。
面试话术
JVM 内存分为线程共享的堆和方法区(元空间),以及线程私有的栈和程序计数器。堆存对象,栈存方法调用。JDK 8 的元空间替代了永久代,使用本地内存避免 OOM。
关键是要能说出每个区域存什么、什么时候会 OOM 或 StackOverflow。
评论
评论已关闭。