Java 真实面试专题

13 篇 · 免费在线阅读

JVM 面试题精选

Java 后端真实面试专题 · JVM 篇

JVM 是真实面经里反复被追问、也是学员最常答不上来的硬骨头。每题三段: ① 标准答(讲透)→ ② 拓展(成体系带出关联点和必追问的)→ ③ 怎么接到你自己的项目

年限标签:🟢 3年内 🔴 3年+


1. 🟢 JVM 的内存结构(运行时数据区)有哪些?

标准答

  • 线程共享:堆(对象实例,GC 主战场)、方法区/元空间(类信息、常量、静态变量)。
  • 线程私有:虚拟机栈(每个方法一个栈帧,存局部变量、操作数栈)、本地方法栈(native 方法)、程序计数器(当前执行的字节码行号)。

拓展

  • "哪些区域会 OOM?"——堆(对象太多)、栈(递归太深 StackOverflowError)、元空间(类太多)。
  • "程序计数器为什么不会 OOM?"——它只存一个行号,唯一不会 OOM 的区域。
  • JDK8 把永久代换成了元空间(用本地内存)。

往项目引 ⭐:"理解内存结构是排查 OOM 的基础——我项目出过堆 OOM(大对象/内存泄漏)和元空间 OOM(动态生成类太多),知道是哪块区域才能对症下药。"


2. 🟢 堆和栈有什么区别?

标准答

  • :线程私有,存方法的局部变量、对象引用,方法调用入栈、结束出栈,自动回收,速度快。
  • :线程共享,存对象实例本身,由 GC 管理回收,空间大但慢。 简单说:栈管"引用和基本类型",堆管"对象"

拓展

  • "对象一定在堆上吗?"——不一定,JIT 的逃逸分析可能做栈上分配/标量替换(对象没逃出方法就放栈上)。
  • "栈溢出和堆溢出?"——栈溢出(StackOverflowError,递归过深)、堆溢出(OutOfMemoryError)。

往项目引 ⭐:"我项目排查过一次 StackOverflowError——是一段递归没正确终止导致栈帧无限叠加。理解栈的机制让我一看异常就知道是递归或调用太深的问题。"


3. 🟢 new 一个对象的过程是什么?

标准答:① 检查类是否已加载,没加载先类加载;② 在上分配内存(指针碰撞或空闲列表);③ 内存初始化零值;④ 设置对象头(类型指针、Mark Word);⑤ 执行构造方法(init)赋初值。

拓展

  • "分配内存怎么保证并发安全?"——CAS + 重试,或用 TLAB(每个线程一块私有分配缓冲)。
  • "对象头里有什么?"——Mark Word(锁状态、hashcode、GC 年龄)+ 类型指针。
  • 这题能引到对象内存布局、锁升级(锁信息在 Mark Word)。

往项目引 ⭐:"理解 new 的过程帮我串起了很多知识——比如 synchronized 的锁状态就存在对象头 Mark Word 里,对象的 GC 年龄也在那,面试时能从'new 对象'自然延伸到锁和 GC。"


4. 🟢 类的加载过程?什么是双亲委派?

标准答:类加载五步——加载(读字节码)→ 验证(校验合法性)→ 准备(静态变量分配内存赋零值)→ 解析(符号引用转直接引用)→ 初始化(执行 static 代码、赋真实值)。 双亲委派:类加载请求先交给父加载器,父加载不了才自己加载(应用类加载器 → 扩展类加载器 → 启动类加载器逐级向上委派)。

拓展

  • "双亲委派的好处?"——保证核心类(如 java.lang.String)不被篡改、避免重复加载。
  • "怎么打破双亲委派?"——重写 loadClass(如 Tomcat 每个 webapp 独立类加载器、JDBC 的 SPI)。
  • 准备阶段静态变量是零值,初始化阶段才赋真实值。

往项目引 ⭐:"我项目用 SPI 机制加载第三方实现(如不同的支付/存储驱动),它就是打破双亲委派、用线程上下文类加载器加载实现类——理解类加载让我看得懂这种'插件式'扩展。"


5. 🔴 怎么判断一个对象可以被回收?(垃圾判定)

标准答:两种算法——

  • 引用计数:对象被引用次数为 0 就回收。缺点:解决不了循环引用,所以 JVM 不用它。
  • 可达性分析(JVM 用):从 GC Roots(栈中引用的对象、静态变量、常量、native 引用等)出发往下搜索,搜不到的对象就是垃圾。

拓展

  • "GC Roots 有哪些?"——虚拟机栈引用的对象、方法区静态属性/常量引用的对象、本地方法栈引用的对象。
  • "对象被判死一定立刻回收吗?"——不,还有一次 finalize 自救机会(但不推荐用 finalize)。
  • 引出四种引用:强、软、弱、虚(见后题)。

往项目引 ⭐:"理解可达性分析帮我理解了内存泄漏的本质——对象其实没用了,但还被某个 GC Roots(如静态集合、ThreadLocal)引用着,所以一直回收不掉。排查泄漏就是找这种'本该死却还被引用'的对象。"


6. 🔴 垃圾回收算法有哪些?分代收集是什么?

标准答

  • 标记-清除:标记垃圾再清除,简单但产生内存碎片
  • 复制:内存分两半,存活对象复制到另一半,无碎片但浪费空间,适合对象存活率低的新生代
  • 标记-整理:标记后把存活对象移到一端,无碎片,适合存活率高的老年代
  • 分代收集:把堆分新生代(复制算法)和老年代(标记整理),不同代用最合适的算法。

拓展

  • "为什么分代?"——大部分对象朝生夕死(新生代用复制最划算),少数长期存活(老年代用标记整理)。
  • 新生代分 Eden + 两个 Survivor(8:1:1),对象先进 Eden,Minor GC 后存活的进 Survivor。

往项目引 ⭐:"理解分代让我能看懂 GC 日志——大部分 GC 是新生代的 Minor GC(很快),频繁 Full GC 才是问题信号。我项目调优就是盯着别让对象过早进老年代、减少 Full GC。"


7. 🔴 对象什么时候从新生代进入老年代?

标准答:几种情况——① 年龄达到阈值(每次 Minor GC 存活年龄 +1,默认到 15 进老年代);② 大对象直接进老年代(避免在 Survivor 来回复制);③ 动态年龄判定(Survivor 中同年龄对象超一半,大于该年龄的直接晋升);④ Survivor 放不下,提前进老年代。

拓展

  • "为什么大对象直接进老年代?"——大对象复制成本高,直接放老年代省事。
  • "对象过早进老年代有什么问题?"——老年代满得快、Full GC 变频繁,是调优要避免的。

往项目引 ⭐:"我项目调过一次 Full GC 频繁——发现是有批量大对象(大集合)频繁进老年代。优化了对象大小和生命周期、调大新生代,Full GC 明显减少。理解晋升机制才能这么调。"


8. 🔴 有哪些垃圾回收器?G1 的设计思想是什么?

标准答

  • Serial:单线程,STW,适合客户端/小堆。
  • Parallel Scavenge:多线程,吞吐优先,JDK8 默认。
  • CMS低停顿、并发标记清除,但有碎片和 concurrent mode failure,已废弃。
  • G1(JDK9+ 默认):把堆分成多个 Region,可预测停顿时间、优先回收垃圾最多的 Region(Garbage First),兼顾吞吐和低停顿。
  • ZGC/Shenandoah:超低停顿(ms 级),适合大堆。

拓展

  • "G1 和 CMS 区别?"——G1 用 Region 化、能控停顿目标(-XX:MaxGCPauseMillis)、整体上是标记整理无碎片。
  • "怎么选 GC?"——吞吐优先选 Parallel,低延迟选 G1/ZGC。

往项目引 ⭐:"我项目用 G1,设了停顿时间目标,兼顾吞吐和延迟。面试被问'你用哪个 GC、为什么'时,我能答出'G1 + Region 化 + 可控停顿',并说我们怎么根据停顿和吞吐监控调参数。"


9. 🔴 G1 什么时候触发 Full GC?

标准答:G1 设计上尽量用 Mixed GC(混合回收)避免 Full GC,但以下情况会触发 Full GC(早期 G1 是单线程 Full GC、很慢):老年代空间不足、并发标记没跟上分配速度(分配失败)、元空间不足、显式 System.gc()

拓展

  • G1 的 Full GC 是要极力避免的(会长 STW)。
  • 避免方法:调大堆/调整 Region、降低对象分配速率、避免大对象、调 InitiatingHeapOccupancyPercent 让并发标记早点开始。
  • JDK10+ G1 Full GC 改成并行、快了些。

往项目引 ⭐:"我项目监控里盯着 G1 的 Full GC——一旦出现就要查是不是分配太快、并发标记跟不上。调过 IHOP 让标记提前启动,避免来不及回收触发 Full GC。"


10. 🟢 Minor GC、Full GC 的区别?什么是 STW?

标准答

  • Minor GC(Young GC):回收新生代,频繁但快。
  • Full GC:回收整个堆(含老年代)+ 方法区,慢、停顿长,要尽量减少。
  • STW(Stop The World):GC 时暂停所有用户线程,停顿期间应用无响应。GC 优化核心就是减少 STW 时间和频率。

拓展

  • "Full GC 频繁的原因?"——内存泄漏、大对象、老年代太小、元空间不足、显式 System.gc()。
  • 几乎所有 GC 都有 STW(CMS/G1 把并发标记部分并发化以减少 STW)。

往项目引 ⭐:"我项目把'Full GC 次数和耗时'作为核心监控指标——Full GC 频繁 = 有内存问题。一次告警就是内存泄漏导致老年代填满频繁 Full GC,定位修复后恢复。"


11. 🔴 线上 CPU 飙高怎么排查?

标准答

  1. top 找到 CPU 高的进程 pid。
  2. top -Hp pid 找到该进程里 CPU 高的线程 tid。
  3. 线程 tid 转 16 进制printf %x)。
  4. jstack pid 导出线程栈,搜那个 16 进制 nid,定位到具体代码。 常见原因:死循环、频繁 GC、正则回溯、锁竞争。

拓展

  • 如果是 GC 导致 CPU 高,jstack 会看到 GC 线程,要去看 GC 日志。
  • Arthasthread 命令能更方便地定位忙线程。

往项目引 ⭐:"我项目处理过一次线上 CPU 100%——top -Hp + jstack 定位到一段异常导致的死循环,10 分钟修复。有这套完整命令链,面试官会觉得你真扛过线上事故。"


12. 🔴 内存溢出(OOM)和内存泄漏的区别?怎么排查 OOM?

标准答

  • 内存泄漏:对象用完了但还被引用、回收不掉,越积越多,最终导致内存溢出
  • 内存溢出(OOM):申请内存时没有足够空间,抛 OutOfMemoryError。 泄漏是因、溢出是果。排查 OOM:加 -XX:+HeapDumpOnOutOfMemoryError 导出堆 dump,用 MAT/JProfiler 分析大对象和引用链(GC Roots 到大对象的路径),找泄漏点。

拓展

  • 常见泄漏点:静态集合一直 add 不删、ThreadLocal 没 remove、连接/流没关、缓存无上限。
  • 不是所有 OOM 都是泄漏——也可能是真的需要那么多内存(要扩容)或大对象。

往项目引 ⭐:"我项目排查过内存泄漏——dump 分析发现是一个静态 Map 当缓存用、只加不删,越积越大。改成有上限的 LRU 缓存(或加过期)后解决。能讲'dump → MAT → 找引用链'这套流程很加分。"


13. 🔴 JVM 调优一般调什么?

标准答:核心目标是减少 Full GC 频率和停顿。常调:

  • 堆大小 -Xms/-Xmx(设相等避免动态扩容抖动)。
  • 新生代大小 -Xmn(让短命对象在新生代回收,别过早进老年代)。
  • 选合适的 GC(吞吐选 Parallel、低延迟选 G1)。
  • G1 的停顿目标 -XX:MaxGCPauseMillisInitiatingHeapOccupancyPercent

拓展

  • 调优要先监控定位再调(GC 日志、监控平台),别凭感觉。
  • 很多"GC 问题"其实是代码问题(内存泄漏、大对象),先查代码。

往项目引 ⭐:"我项目调优是数据驱动的——先看 GC 日志和监控(Full GC 频率、停顿、各代占用),定位是对象过早晋升,再调新生代大小和晋升阈值。不是上来就堆参数。"


14. 🔴 JDK8 的内存模型相比之前有什么变化?

标准答:最大变化是永久代(PermGen)被元空间(Metaspace)取代。永久代在堆里、大小固定容易 OOM;元空间用本地内存、默认随需扩展,存类元信息。同时字符串常量池从永久代移到了堆。

拓展

  • "为什么改?"——永久代大小难调、容易 PermGen OOM;元空间用本地内存更灵活。
  • 元空间也会 OOM(动态生成类太多,如大量 CGLIB 代理),可用 -XX:MaxMetaspaceSize 限制。

往项目引 ⭐:"我项目是 JDK8/11,知道元空间用本地内存——排查过一次元空间 OOM,是某框架动态生成代理类太多。理解这个变化才知道去看元空间而不是堆。"


15. 🔴 强引用、软引用、弱引用、虚引用的区别?

标准答

  • 强引用:普通的 new,只要引用在就不回收(OOM 也不回收)。
  • 软引用(SoftReference):内存不足时才回收,适合做缓存
  • 弱引用(WeakReference):下次 GC 就回收,如 ThreadLocalMap 的 key、WeakHashMap。
  • 虚引用(PhantomReference):随时可能被回收,用于在对象回收时收到通知(管理堆外内存)。

拓展

  • "ThreadLocal 为什么 key 用弱引用?"——让 ThreadLocal 对象本身能被回收,但 value 是强引用还在,所以要 remove(内存泄漏点)。
  • 软引用缓存在内存紧张时自动释放,是一种优雅降级。

往项目引 ⭐:"我项目本地缓存用过软引用——内存够时缓存命中、内存紧张时自动被回收,避免缓存把内存撑爆 OOM。也理解了 ThreadLocal 弱引用 key + 强引用 value 为什么必须 remove。"


16. 🟢 什么是 JIT?解释执行和编译执行?

标准答:Java 字节码先解释执行(一行行翻译),JVM 的 JIT(即时编译器) 会把热点代码(频繁执行的方法/循环)编译成本地机器码缓存起来,后续直接执行,大幅提速。

拓展

  • "怎么判断热点?"——方法调用计数 + 循环回边计数。
  • JIT 还会做逃逸分析、内联、栈上分配等优化。
  • 所以 Java"越跑越快"(热点被编译后)。

往项目引 ⭐:"理解 JIT 让我知道为什么压测要'预热'——刚启动是解释执行慢,跑一会热点被 JIT 编译后才到稳定性能,所以压测数据要看预热后的。"


17. 🔴 类加载器有哪几种?

标准答

  • 启动类加载器(Bootstrap):加载 JAVA_HOME/lib 核心类(C++ 实现)。
  • 扩展类加载器(Extension):加载 lib/ext
  • 应用类加载器(Application):加载 classpath 下我们写的类。
  • 自定义类加载器:继承 ClassLoader 实现特殊加载(热部署、加密类、隔离)。 它们按双亲委派协作。

拓展

  • "Tomcat 为什么自定义类加载器?"——每个 webapp 一个类加载器,实现应用间类隔离(同名类不冲突),打破了双亲委派。
  • 热部署、模块化(OSGi)也靠自定义类加载器。

往项目引 ⭐:"我项目部署在 Tomcat,多个应用各自的类加载器隔离,所以不同应用用不同版本的同名 jar 不会冲突——理解类加载器才明白这种隔离是怎么来的。"


18. 🟢 String 创建了几个对象?字符串常量池了解吗?

标准答String s = "abc" 在常量池里有就复用、没有就创建一个;String s = new String("abc") 创建两个(常量池一个 + 堆里一个),返回堆里的引用。intern() 能把字符串放入/返回常量池的引用。

拓展

  • "为什么 String 不可变?"——安全(做 key、参数)、可缓存 hashcode、支持常量池复用。
  • JDK7+ 字符串常量池在堆里(之前在永久代)。
  • 大量字符串拼接用 StringBuilder,别用 +(每次生成新对象)。

往项目引 ⭐:"我项目里高频拼接(如拼 SQL、拼日志)一律用 StringBuilder,循环里用 + 会产生大量临时 String 对象、加重 GC——理解 String 不可变和常量池才知道为什么。"


19. 🟢 happens-before 和 Java 内存模型(JMM)了解吗?

标准答:JMM 规定了多线程下共享变量的可见性、有序性规则。每个线程有自己的工作内存,改了共享变量要刷回主内存别人才看得到。happens-before 是判断"前一个操作的结果对后一个操作是否可见"的规则,如:锁的解锁 happens-before 后续加锁、volatile 写 happens-before 后续读。

拓展

  • JMM 解决的是并发三大问题里的可见性和有序性。
  • volatile、synchronized、final 都是靠 JMM 规则保证可见性/有序性。
  • 和 JVM 内存结构(堆栈)是两码事,别混。

往项目引 ⭐:"理解 JMM 让我知道为什么并发下共享变量要加 volatile 或锁——不是值没改,是改了没及时刷到主内存、别的线程看到旧值。我项目状态标志位加 volatile 就是为了可见性。"


20. 🟢 你项目里有没有做过 JVM 相关的排查或优化?

标准答:结合真实经历讲——如排查 OOM(dump + MAT 找泄漏)、CPU 飙高(top -Hp + jstack)、Full GC 频繁(GC 日志定位对象晋升问题调参数)。讲清"现象 → 工具 → 定位 → 解决"。

拓展

  • 没真实经历也别瞎编,可以说"了解排查思路"并把方法论讲清。
  • 工具:jstack、jmap、jstat、MAT、Arthas、GC 日志。

往项目引 ⭐:"我项目处理过 CPU 飙高(jstack 定位死循环)和内存泄漏(MAT 定位静态缓存只增不减),都是'现象→工具→定位→修复'的完整闭环。哪怕年限不长,能讲出一次真实排查经历就比纯背 JVM 概念强。"


你能答到第几层?

  • 三段都能答、还能往项目引:JVM 这块你超过大多数候选人了。
  • 标准答 + 拓展能成体系答:知识扎实,差把它接到一次真实排查/调优经历上。
  • 标准答都磕巴:JVM 有主线(内存结构 → 类加载 → GC → 调优排查),跟着学一遍 + 动手做一次 OOM/GC 排查就懂。

这是面试专题的「JVM 篇」,网站上还有并发、MySQL、Redis、Spring、微服务、消息队列、项目场景等系统整理。 🌐 更多真实面试专题与资料:smallredtech.com 💬 想系统学 / 简历与辅导咨询,加微信:Ahongbb666(备注「面试题」)