JVM 内存与垃圾回收,面试官最爱问的几件事
从内存区域到 GC Roots、垃圾收集器演进、双亲委派——按"一个对象从 new 到被回收"这条线讲清楚。

JVM 这块我吃过亏。面试时能背出"堆、栈、方法区"的人一大把,但一问"一个对象从 new 出来到被回收,中间经历了什么",很多人就卡住了。这篇我就按这条线讲,顺便带上我自己的理解,而不是报菜名。
内存先分清楚:哪些线程私有,哪些共享
JVM 运行时内存分两大块。
线程私有的,每个线程一份:
- 程序计数器:记当前线程执行到字节码第几行了。这玩意儿小,也不会 OOM,因为每个线程只管自己。
- 虚拟机栈:一个方法一个栈帧,里面装局部变量表、操作数栈这些东西。方法调方法,栈帧一层层叠,叠太深就 StackOverflowError。
- 本地方法栈:给 Native 方法用的,Java 代码一般碰不到。
线程共享的:
- 堆:对象实例都在这,垃圾回收的主战场,也是最容易 OOM 的地方。
- 方法区:存类信息、常量、静态变量。JDK 8 之后换成了元空间(Metaspace),直接用本地内存,不再受堆大小管。
面试常问"哪里会 OOM",我的习惯是先区分两种错误:OutOfMemoryError 是资源真耗尽了,StackOverflowError 是栈深度超了——这俩不是一回事,别混着答。
一个对象怎么被判"该回收了"
主流方案是可达性分析:从一组叫 GC Roots 的起点出发,顺着引用链往下找,够不着的对象就是垃圾。
GC Roots 都有哪些?虚拟机栈里引用的对象、类的静态属性、常量池里的常量、JNI 引用的对象、还有被 synchronized 锁住的。背全不容易,但可以理解成"任何还活着的入口"。
再配一个引用类型的知识点:
- 强引用:只要还有引用,OOM 都不回收;
- 软引用:内存够就留着,不够了才收,适合做缓存;
- 弱引用:下一次 GC 就收,ThreadLocal 的 key 就是它;
- 虚引用:基本收不到什么,主要配合直接内存的清理。
回收算法:为什么新生代和老年代打法不一样
三大基础算法,名字记不住不要紧,理解它们的取舍就行:
- 标记-清除:最朴素,标记出垃圾再清掉。缺点是清完有碎片。
- 标记-复制:把空间一分为二,活的搬过去,整个另一半直接清空。新生代就靠它,因为活对象少,搬起来便宜。Eden 和两块 Survivor 区按 8:1:1 分,就是这个道理。
- 标记-整理:活的往一头挪,消除碎片。老年代用它,因为老年代活对象多,复制成本太高,整理一下更划算。
为什么新生代用复制、老年代用整理?因为对象大多"朝生夕死"——新生代里绝大多数活不过第一次 GC,复制代价低;老年代熬过好多轮 GC 了,存活率高,复制不划算,整理才合适。
收集器演进:从 Parallel 到 ZGC
这一块面试官喜欢问你"用哪个"。
- Serial / Parallel:一个单线程一个多线程,吞吐优先的旧选择,年轻代还常见。
- CMS:当年为低停顿设计的,但会产生碎片,JDK 9 标记废弃、JDK 14 移除,别再往简历上写了。
- G1:JDK 9 起默认。把堆分成许多小块(Region),每次挑垃圾最多的区域回收,停顿时间可预测。现在生产上跑 Java 的默认就是它。
- ZGC:低延迟路线,目标是停顿控制在 10ms 以内,JDK 21 之后默认开分代模式。堆特别大、又受不了停顿的场景选它。
我给自己的选择题:图省事用默认的 G1;吃吞吐量、堆又小用 Parallel;堆大又对延迟敏感用 ZGC。
类加载:双亲委派是干嘛的
类的一生:加载 → 验证 → 准备 → 解析 → 初始化。记住这个顺序就行,里面最常被问的是双亲委派。
双亲委派的意思:一个类加载器接到"加载某个类"的请求,自己不先动手,而是往上抛给父加载器,父加载器也抛,最后轮到最顶层的启动类加载器。都加载不了,才一层层往下自己动手。
为什么要这么绕?核心就一条:保证核心类的唯一性。不然你自己写个 java.lang.String 扔 classpath 里,就可能把 JDK 自带的 String 顶掉,整个系统就乱了。
有没有打破它的场景?有,典型的是 SPI(ServiceLoader、JDBC 驱动那套)和 Tomcat。SPI 的问题是"父加载器加载的代码要调用子加载器才有的实现",只能通过线程上下文类加载器反着来。问到这个能答出 SPI,一般就过关了。
关于 JDK 版本,值得记两句
不背版本号,但提两句能显得你真的在跟进:JDK 25(2025 年 9 月)是目前最新的 LTS;JDK 26 非 LTS,比较值得说的是带来了 HTTP/3 支持和更强的反射 API。面试时顺口提一句"现在 LTS 线是 21 / 25",比干巴巴背八股强。
高频追问
String为什么不可变?(缓存、安全、当 key 放心)==和equals、hashCode和equals的关系?synchronized锁升级的过程?- 内存泄漏常见场景?(长生命周期对象抱着短命对象不放、静态集合、
ThreadLocal用了不remove)
最后说句实在的:JVM 面试最值钱的不是记住每个概念,而是能把"一个对象从 new 到被回收"这条链完整讲下来——从分配内存、到躲过几轮 GC、再到被标记回收。这条链通顺了,JVM 基本就稳了。