← 返回软件技术总览 软件技术 · 知识点深化 · JVM 内存模型:堆/栈/方法区/程序计数器
知识点深化 · JVM · 内存模型

JVM 内存模型:堆/栈/方法区/程序计数器

JVM 把进程内存划分为若干区域:堆放对象、虚拟机栈放方法栈帧、方法区放类元数据、程序计数器记当前指令。理解这块是排查 OOM、StackOverflow、GC 的前提。这一页把五个区域的职责、线程共享与否、存什么讲透。

① 小白第一课怎么学(4 步走,约 60 分钟)

别急着背代码,先按这四步建立直觉:

1看图建立直觉(10 分钟)
读②③:把 JVM 想成一个分工明确的仓库。
2记五块区域(15 分钟)
读④:每块存什么、谁共享、溢出抛啥。
3手画内存布局(20 分钟)
精读⑤。
4刷题纠错(15 分钟)
做⑦⑩,错题回⑥。
本课小目标学完你要能:① 说出 JVM 五块内存;② 区分线程私有/共享;③ 定位哪块溢出会抛什么异常。

② 一图看懂:JVM 内存全地图

JVM 运行时数据区 程序计数器 私有/记指令行号 虚拟机栈 私有/栈帧局部变量 堆 Heap 共享/对象实例/GC 区 方法区 共享/类元数据常量 本地方法栈 私有/native 方法 异常:堆 OOM / 栈 SOE 调 -Xmx -Xss 易错:把栈当对象存 对象在堆,引用在栈
读法:中心是 JVM 运行时数据区,左线程私有右线程共享,下是异常与易错。

③ 本质直觉:栈放"干活的现场",堆放"造好的对象"

虚拟机栈(线程私有):每调一个方法就压一个栈帧,里面放局部变量表、操作数栈、返回地址。方法返回栈帧弹出。递归太深栈帧太多就 StackOverflowError。

堆(线程共享):new 出来的对象都在堆里,是 GC 主战场。堆满了又回收不掉就 OutOfMemoryError: Java heap space。

方法区(共享):存类的元信息、常量池、静态变量。JDK8 后用本地内存的元空间 Metaspace实现。

程序计数器(私有):记当前线程执行到哪条字节码,唯一个不会 OOM 的区域。

线程私有(左)vs 共享(右) 每个线程一份 程序计数器 虚拟机栈 本地方法栈 所有线程共享 堆 Heap(对象) 方法区/元空间 运行时常量池 对象在堆,局部变量在栈帧里存引用 Xmx 控堆,Xss 控栈帧大小
对象到底在哪Object o = new Object();:引用 o 在栈帧局部变量表,真正的 Object 对象在堆。栈里存的只是地址指针。

④ 完整体系与对比表

五块区域总表

区域线程共享存什么溢出异常
程序计数器私有当前字节码行号无 OOM
虚拟机栈私有栈帧:局部变量、操作数栈StackOverflowError / OOM
本地方法栈私有native 方法同上
堆共享对象实例、数组OOM: Java heap space
方法区/元空间共享类元数据、常量、静态变量OOM: Metaspace

常见 JVM 参数

参数作用
-Xms堆初始大小
-Xmx堆最大大小
-Xss每个线程栈大小(默认 512K~1M)
-XX:MetaspaceSize元空间初始上限

⑤ 用法场景与典型例题

例1(定位)递归无限调用方法,抛什么异常?
栈帧不断压栈。
栈帧太多超过栈深度 → StackOverflowError。调大 -Xss 治标,修递归才治本。
例2(定位)不断 new 对象且不释放,抛什么?
堆满了 GC 也回收不掉。
堆 OOM: Java heap space。是内存泄漏或堆太小。
例3(局部变量)方法内 int x=5,x 存在哪?
基本类型局部变量在栈帧。
局部变量表在虚拟机栈帧里;若是对象 new 出来的,对象本体在堆,栈里只存引用。
做题心法看到 StackOverflow 想栈太深;看到 heap space OOM 想堆/内存泄漏;看到 Metaspace OOM 想类加载太多。

⑥ 高频错误诊断(4 条)

错误1:以为对象存在栈上new 的对象在堆,栈里只放引用/局部变量。
错误2:以为程序计数器会 OOM它是唯一不会 OOM 的区域,只记行号。
错误3:混淆方法区和堆方法区存类元数据和常量,不存对象实例。
错误4:JDK8 还说永久代 PermGenJDK8 已用元空间 Metaspace(本地内存)替代永久代。

⑦ 考点真题演练(4 题)

考点分布

考法出题形式应对
五块区域问存什么/谁共享背总表
异常定位抛啥异常对应哪块栈 SOE,堆 OOM
对象位置new 的对象在哪堆
JDK8 变化永久代换成什么元空间

真题基础1. new 出来的对象实例主要分配在?

真题中档2. 递归调用过深会抛出?

真题中档3. JDK8 后方法区由什么实现?

真题拔高4. 下列哪个区域是线程私有的?

⑧ 必背知识点卡

程序计数器:私有,记指令行号,不 OOM
虚拟机栈:私有,栈帧局部变量,SOE 递归太深
堆:共享,对象实例,GC 主战场 heap OOM
方法区:共享,类元数据常量,JDK8 元空间 Metaspace
对象:本体在堆,引用在栈
参数:-Xmx 堆,-Xss 栈
栈帧:局部变量表+操作数栈+返回地址

⑨ 应用输出:排查一次线上 OOM 事故

场景:服务频繁 Full GC 后抛 java.lang.OutOfMemoryError: Java heap space。
① 定位区域:异常是 heap space,说明堆放不下了。
② 加参数:-XX:+HeapDumpOnOutOfMemoryError 让 OOM 时自动 dump 堆快照。
③ 分析 dump:用 MAT/jvisualm 看哪个对象占用最大——若一个集合一直涨不清就是内存泄漏。
④ 对策:修复泄漏代码;临时可 -Xmx 调大堆。
⑤ 区分:若是 StackOverflow 则是递归太深,若是 Metaspace OOM 则类加载过多(如动态生成类)。
口述思路合上书说:"heap OOM 先 dump 堆快照找大对象,SOE 查递归。"

⑩ 分层练习(基础 + 中档 + 拔高)

▍基础 6 题

基础1JVM 五块内存区?
PC 计数器、虚拟机栈、本地方法栈、堆、方法区。
基础2对象实例在哪个区?
堆。
基础3线程私有的有哪些?
PC 计数器、虚拟机栈、本地方法栈。
基础4递归太深抛什么?
StackOverflowError。
基础5-Xmx 控制什么?
堆最大大小。
基础6JDK8 方法区叫什么?
元空间 Metaspace。

▍中档 6 题

中档7局部变量 int x 存在哪?
虚拟机栈帧的局部变量表。
中档8GC 主要回收哪块?
堆里的死对象。
中档9哪个区不会 OOM?
程序计数器。
中档10静态变量存在哪?
方法区/元空间(JDK8 后在元空间)。
中档11栈帧里有什么?
局部变量表、操作数栈、动态链接、返回地址。
中档12堆满了抛什么?
OutOfMemoryError: Java heap space。

▍拔高 6 题

拔高13为什么元空间用本地内存而不占堆?
避免类加载过多撑爆堆,上限默认 -XX:MaxMetaspaceSize。
拔高14直接内存 DirectByteBuffer 属于哪?
不在 JVM 五区里,是堆外本地内存,受 -XX:MaxDirectMemorySize 限制。
拔高15栈帧大小默认多少?
-Xss 默认约 512K~1M,决定了栈能压多深。
拔高16对象一定在堆吗?
JIT 逃逸分析后可能栈上分配/标量替换,不进堆。
拔高17方法出口地址存在哪?
栈帧的返回地址区。
拔高18常量池在哪个区?
方法区(运行时常量池)。

⑪ 记忆口诀 + 7 天复习计划

三句口诀① 栈私有人干活,堆共享放对象。② 方法区存类元数据,JDK8 改元空间。③ 递归太深 SOE,堆满 heap OOM。
天任务自检
第 1 天读②③④,画五区图谁私有谁共享对
第 2 天背总表 + 基础 1-6异常对应对
第 3 天做中档 7-12,定位对象位置栈/堆分清
第 4 天做拔高 13-18,理解逃逸分析能讲清栈上分配
第 5 天做⑦真题 4 题限时每题 2 分钟
第 6-7 天合上书默写五区表不看资料全默对

← 返回软件技术总览