JVM 内存区域有哪些?堆、虚拟机栈和元空间分别存什么?
下面是一段教学用的模拟面试。
🧑💻 面试官:Java 的对象存在哪里?
🙋♂️ 我:对象在堆里,局部变量在栈里。
🧑💻 面试官:方法里的局部变量引用了一个对象。这个对象也跟着进入栈了吗?
🙋♂️ 我:没有,栈里的变量可以保存指向对象的引用。
🧑💻 面试官:那应用报 Metaspace 内存不足,把最大堆调大能解决吗?你说的方法区和元空间又是什么关系?
先抓住「装的是什么、谁在使用」:方法调用过程、对象实例和类元数据,不能都当成同一块内存。
面试速答(60 秒版)
JVM 规范把运行时内存分成程序计数器、虚拟机栈、堆、方法区和本地方法栈等逻辑区域,运行时常量池属于方法区的一部分。
程序计数器和虚拟机栈是线程私有的。每次方法调用都会对应一个栈帧,保存局部变量、操作数栈等执行信息。堆则供线程共享,在逻辑上分配对象实例和数组。
方法区保存类相关的结构。在现代 HotSpot 中,类元数据主要使用本地内存中的 Metaspace,但元空间不能简单替代规范里方法区的全部含义。例如 JIT 编译后的机器代码还有自己的 Code Cache。
排查内存问题时,先看错误发生在哪个区域。栈深度、堆中的对象保留和类元数据增长,需要用不同证据分析,不能一看到内存不足就调大 Xmx。

知识点详解:沿着一次方法调用认识这些区域
方法在执行,栈里就会留下它的执行现场
假设一个请求进入 service 方法,service 再调用 parse 方法。
线程调用 service 时建立一个栈帧,调用 parse 时又建立一个。parse 结束后,其栈帧退出,线程回到 service 继续执行。
栈帧里的局部变量可以保存数值,也可以保存对象引用。一个引用在栈里,不意味着它指向的整个对象也在栈里。不同线程还可能通过不同引用访问同一个共享对象。
程序计数器则帮助描述当前线程执行到哪条 JVM 指令。切换线程以后,各线程有自己的执行位置,不会共用一个进度标记。
对象在堆里,方法结束也未必消失
继续假设 service 调用 parse,而 parse 在处理时创建一个结果对象。parse 返回后,它自己的栈帧退出,service 用 result 接住返回值,仍然引用着这个对象。
如果 service 随后再把结果返回给外层调用者,道理也一样:service 的栈帧虽然退出了,只要调用者还持有这个结果,对象就不会仅仅因为方法结束而被回收。
因此,栈帧的生命周期跟着方法调用走,对象的存活则要看引用关系。这两个问题不要混在一起。
JVMS 25规定堆用于对象实例和数组的逻辑分配。实际实现可以通过逃逸分析等优化消除某些分配,所以也不要把“每个 new 都一定留下一个实际堆对象”说成不可优化的物理事实。

方法区是规范名称,元空间是实现里的概念
JVM 需要知道一个类有哪些字段、有哪些方法,以及相关的运行时常量等结构。这些属于类层面的信息,不是某一个用户对象的实例数据。
方法区描述的是这类信息所在的逻辑区域。HotSpot 的 Metaspace 主要管理类元数据,使用本地内存。JDK 8 以后的相关实现,不应该再用永久代作为当前默认解释。
同时,实例字段数据、类元数据、Class 对象和 JIT 机器代码,也不是一看到“类”字就都放进同一处。面试中先说清规范与实现的区别,比画一张过度简化的“元空间装所有方法相关内容”更稳妥。
三种内存异常,先查三个不同方向
如果报 StackOverflowError,先检查调用链是不是太深,例如没有退出条件的递归。增加栈大小可能只是把失败推迟,不解决递归逻辑。
如果报 Java heap space,要看堆中的对象为什么增长:请求积压、大结果集、缓存没有边界,还是对象本该释放却仍被引用。可以结合堆转储、对象数量和引用路径分析。
如果报 Metaspace,要检查类加载数量和类加载器生命周期。动态生成代理类、反复加载插件但旧加载器没有释放,都可能让类元数据持续保留。只调大堆容量不对应这个区域。
当然,进程总内存还包括其他本地内存,不能拿 Java 堆大小代表整个进程的内存消耗。

面试官继续追问
栈是私有的,就说明线程一定不会相互影响吗?
不说明。线程私有的是调用栈,栈里的引用仍可能指向共享对象。两个线程访问同一个可变对象,仍需要正确的并发控制。
元空间使用本地内存,是不是就没有上限了?
不是。它仍受进程与操作系统可用内存约束,也可以配置相应上限。本地内存不是免费内存,更不是无限内存。
怎么区分对象增长和类增长?
查看堆中主要对象的数量与保留路径,同时观察已加载类、类加载器和元空间使用情况。收集证据要对应症状;堆转储并不能单独代表所有本地内存情况。
面试速记卡
- 栈:线程的方法调用现场,按栈帧管理执行信息。
- 堆:逻辑上的对象实例与数组分配区域,线程共享。
- 方法区:规范中的类相关逻辑区域。
- Metaspace:HotSpot 类元数据实现,不能概括所有方法区内容。
- 排错:先定位区域,再看调用深度、对象保留或类加载器。
公司面试真题
真题根据求职者公开面经整理,题意经过概括,非逐字原话或公司官方题库;本文为 Sunday 的独立解析。
美团 · Java后端 · 实习
JVM 内存结构分为哪些部分,各有什么作用?(题意整理)
4.21美团Java实习一二面面经 ↗
面试记录为 2020-04-21、2020-04-24;原帖编辑于 2020-11-14京东 · Java后台 · 校招
JVM 内存怎样分区?(题意整理)
京东 Java 后台三面凉经 ↗
原帖编辑于 2019-08-23(历史校招面经)