标准答案
- 程序计数器记录当前线程将要执行的字节码位置;每个线程独立拥有。
- 虚拟机栈保存栈帧、局部变量和调用状态,递归过深或栈帧过大可能导致 StackOverflowError。
- 堆保存对象实例,是垃圾回收的主要区域;类元数据、运行时常量池等由 JVM 实现管理。
- 线程共享区域需要并发安全,线程私有区域不会因为共享访问产生同样的数据竞争。
题目解析
JVM 规范描述的是运行时数据区的语义,不是某个版本 HotSpot 的固定内存图。堆、方法区等共享区域需要考虑并发访问,程序计数器和虚拟机栈则跟着线程生命周期走。
对象通常由堆管理,但局部变量和引用可能位于栈帧中;JIT 还可能通过逃逸分析消除分配或改变实现方式。回答时要区分语言语义、规范要求和运行时优化。
排查内存问题要同时看堆、线程栈、元空间、直接内存和本地资源。只看到进程 RSS 变化,不能直接判断是哪个运行时区域出了问题。
常见误区
- 误区:说所有运行时区域都在线程之间共享。改正:区分线程私有的程序计数器、虚拟机栈与线程共享的堆、类元数据等区域。
- 误区:认为栈保存所有对象。改正:栈帧保存局部变量和引用,对象实例通常由堆管理,具体分配还可能被 JIT 优化。
- 误区:把 JVM 规范概念和 HotSpot 实现混为一谈。改正:先说明规范语义,再补充目标 JDK 和收集器的实现差异。