JVM 运行时数据区分为线程共享和线程私有两类。
线程私有区域:程序计数器(PC 寄存器),记录当前线程执行的字节码行号,是唯一不会 OOM 的区域;Java 虚拟机栈,每个方法调用对应一个栈帧,存放局部变量表、操作数栈、方法返回地址等,栈深不足抛 StackOverflowError,无法扩展时抛 OOM;本地方法栈,服务于 native 方法。
线程共享区域:堆,几乎所有对象实例和数组在此分配,是 GC 的主战场,逻辑上分新生代(Eden + 两个 Survivor)和老年代,堆不足抛 OutOfMemoryError: Java heap space;方法区(JDK 8 之前为永久代,之后改为使用本地内存的元空间 Metaspace),存放类元数据、运行时常量池、静态变量、JIT 编译后的代码等。
另外还有直接内存(NIO 的 DirectByteBuffer),不属于 JVM 规范定义的运行时数据区,但也可能触发 OOM。
追问方向:为什么 JDK 8 移除永久代?(类元数据大小难预估、促进 HotSpot 与 JRockit 合并)字符串常量池在哪个区域?(JDK 7 起移入堆)
(约 350 字)