jvm内存结构分为线程私有区域和线程共享区域:私有区域包括程序计数器(不抛oom)、虚拟机栈(栈溢出或线程过多oom)、本地方法栈;共享区域含堆(对象分配与分代gc)和元空间(类元数据,本地内存),直接内存属堆外非规范区。

JVM 内存结构按线程是否共享,划分为两大类:线程私有区域和线程共享区域。这种划分直接对应内存的生命周期、访问方式和回收策略,是理解 Java 内存行为和排查 OOM、栈溢出等问题的基础。
线程私有区域:每个线程独享,随线程生灭
这类区域不被多个线程共用,天然线程安全,也基本不会引发内存泄漏(除非栈深度失控)。
-
程序计数器:记录当前线程正在执行的字节码指令地址,用于线程切换后恢复执行位置;是 JVM 中唯一不会抛出
OutOfMemoryError的区域。 -
虚拟机栈:每个方法调用对应一个栈帧,存储局部变量表、操作数栈、动态链接和方法返回地址;栈深度超限会抛出
StackOverflowError,若不断创建线程导致内存耗尽则可能触发OutOfMemoryError。 - 本地方法栈:为 JVM 调用 Native 方法(如 JNI)服务,作用和异常类型与虚拟机栈类似。
线程共享区域:所有线程共用,GC 主战场
这些区域由整个 JVM 进程统一管理,生命周期与 JVM 一致,也是内存溢出和垃圾回收最常发生的地带。
- 堆(Heap):JVM 最大内存区域,所有对象实例和数组都在这里分配;默认分代管理——新生代(Eden + S0/S1,默认比例 8:1:1)负责新对象分配和 Minor GC;老年代存放长期存活对象,触发 Major GC 或 Full GC。
-
元空间(Metaspace):JDK 8+ 取代永久代,存储类元数据(类信息、常量、静态变量、JIT 编译代码等);位于本地内存(非堆),OOM 原因通常是加载了过多类(如热部署、反射滥用)或元空间大小配置过小(
-XX:MetaspaceSize/-XX:MaxMetaspaceSize)。
补充说明:直接内存不属于 JVM 规范定义的运行时数据区
它通过 java.nio.DirectByteBuffer 分配,使用本地内存(堆外),不受堆大小参数(-Xmx)限制,但受系统物理内存和 -XX:MaxDirectMemorySize 控制;NIO 高频场景下容易忽略其泄漏风险。










