四要素图:线程私有(程序计数器、栈、本地方法栈)不共享、无OOM风险;线程共享(堆、元空间、直接内存)需防竞争与回收;堆OOM调-Xms/-Xmx,栈溢出调-Xss,元空间OOM调-XX:MaxMetaspaceSize。

直接画一张“分区+归属+异常+调优入口”四要素图,比背概念管用得多。
先分两大阵营:线程私有 vs 线程共享
这是理解所有区域的底层逻辑。JVM 内存不是杂乱堆砌,而是按“会不会被多个线程同时改”来切的:
- 线程私有区:每个线程一份,互不干扰。包括程序计数器、Java 虚拟机栈、本地方法栈。它们随线程生而生、灭而灭。
- 线程共享区:所有线程共用,是 GC 和竞争的主战场。包括堆、元空间(JDK 8+ 的方法区)、直接内存(虽非运行时数据区,但属 JVM 进程内存)。
重点讲清三个高频出问题的区域
不用全讲五块,聚焦堆、栈、元空间——线上 90% 的 OOM 和 StackOverflow 都在这儿:
-
堆(Heap):所有 new 出来的对象都在这儿。新生代(Eden + Survivor)负责短命对象,老年代收长期存活或大对象。OOM 提示是 java.lang.OutOfMemoryError: Java heap space,调优参数是
-Xms/-Xmx。 -
虚拟机栈(VM Stack):每次方法调用压一个栈帧,存局部变量、操作数等。递归太深或单线程栈帧太多就爆,报 StackOverflowError;若系统级线程数过多(比如
new Thread()泛滥),则报 OOM: unable to create new native thread,本质是操作系统内存耗尽,调优靠-Xss控制单个栈大小。 -
元空间(Metaspace):存类定义、常量池、静态变量、JIT 编译代码。它不在堆里,而用的是本地内存。动态生成类(如 Spring CGLIB、热部署、大量反射)容易撑爆它,报 java.lang.OutOfMemoryError: Metaspace,需设
-XX:MaxMetaspaceSize。
捎带两个易忽略但关键的点
讲完主干,加两句就能显深度:
- 程序计数器(PC Register):唯一不会 OOM 的区域,只存当前执行的字节码地址,线程私有、极小、固定大小。
- TLAB(线程本地分配缓冲):堆虽然是共享的,但 JVM 会为每个线程悄悄划一块“自留地”,new 对象优先往这儿写,避免并发加锁。这是理解高并发下对象分配效率的关键细节。
最后用一句话收住
记住:对象在堆,方法在栈,类在元空间,线程私有的不共享,线程共享的要防抢、要回收——图就立住了。


















