jvm内存结构划分为线程私有和线程共享两大类:私有区域含程序计数器、虚拟机栈、本地方法栈,随线程生灭、无线程安全问题;共享区域含堆、方法区(元空间)、运行时常量池、直接内存,由jvm统一管理,是gc主战场和oom高发区。

JVM 内存结构按线程是否共享划分为两大类:线程私有区域和线程共享区域。这种划分直接决定内存的生命周期、线程安全性以及是否参与垃圾回收。理解它,关键不是死记区域名称,而是抓住“谁在用、何时生灭、出问题往哪查”这三点。
线程私有区域:每个线程独享,随线程而生灭
这部分内存不涉及多线程竞争,也不归 GC 管理,但它是方法执行和线程调度的基础支撑。
-
程序计数器:记录当前线程正在执行的字节码指令地址。线程切换回来时靠它恢复执行位置;是唯一不会抛
OutOfMemoryError的区域。 -
Java 虚拟机栈:为每个方法调用分配一个栈帧,存储局部变量(含对象引用)、操作数栈、方法出口等。栈深度超限会触发
StackOverflowError;线程过多导致总栈空间耗尽则报OutOfMemoryError: unable to create new native thread。 - 本地方法栈:作用与虚拟机栈类似,但专用于 JNI 调用的 native 方法(如 C/C++ 代码)。异常类型和调优方式与虚拟机栈基本一致。
线程共享区域:所有线程共用,GC 主战场
这是 Java 对象真正“安家”的地方,也是 OOM 最常发生、性能调优最核心的区域。
-
Java 堆(Heap):所有对象实例和数组的唯一分配地。默认占 JVM 内存最大比例,由 GC 自动管理。HotSpot 中进一步划分为:
- 年轻代:Eden 区(新对象首选地) + 两个 Survivor 区(From/To,存放 Minor GC 后幸存对象);
- 老年代:长期存活对象的归宿,GC 频率低但耗时长;
- TLAB(Thread Local Allocation Buffer):每个线程在 Eden 中的私有小块,提升对象分配效率,无需加锁。
-
方法区(JDK 8+ 为元空间):存储类信息、常量、静态变量、即时编译后的代码等。JDK 8 起,元空间使用本地内存(而非堆内存),避免永久代溢出问题;但若类加载过多(如动态代理泛滥、OSGi 场景),仍可能因本地内存不足抛出
OutOfMemoryError: Metaspace。 - 运行时常量池:属于方法区的一部分,存放编译期生成的各种字面量和符号引用(如字符串常量、类名、字段名);字符串常量池在 JDK 7 后已从方法区移到堆中。
容易被忽略的“非规范”区域:直接内存
它不属于《JVM 规范》定义的运行时数据区,但被 NIO 的 ByteBuffer.allocateDirect() 等方式频繁使用。它绕过 JVM 堆,直接向操作系统申请内存,速度快但需手动管理——如果大量使用又未及时清理,会导致物理内存耗尽,抛出 OutOfMemoryError: Direct buffer memory。
掌握这些区域的职责和边界,就能快速定位典型问题:方法调用爆栈看虚拟机栈,对象创建失败看堆和元空间,NIO 缓冲异常优先查直接内存。不复杂,但容易忽略细节。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











