面试指南

JVM深度

面试权重:★★★ | 适用级别:P7/P8+ | 预计复习时间:1-2周

概览

面试权重:★★★ | 适用级别:P7/P8+ | 预计复习时间:1-2周

这一章的主线不是背收集器名字,而是把"对象如何创建、如何存活、何时被回收、出了问题怎么排查"说成一条完整链路。

建议用法

先把正文里的内存结构、GC、类加载和排障工具串起来,再去刷后面的高频面试题。真正高频的失分点通常不是结论不知道,而是不会把现象、原理、参数和排查动作连起来。

一、知识体系

1. JVM内存结构 ★★★

1.1 运行时数据区

堆、方法区与虚拟机栈
  • 核心结论
    • 对后端面试来说,最重要的不是把所有内存区域按定义背出来,而是知道"谁放对象、谁放类元数据、谁跟线程生命周期绑定"。
    • 堆是对象实例和数组的主要落点,也是 GC 的主战场。
    • 方法区在 HotSpot 中对应元空间,主要放类元数据、运行时常量池、静态变量等。
    • 虚拟机栈是线程私有的,方法调用时会创建栈帧,局部变量表、操作数栈、动态链接都在这里。
  • 原理展开
    • 堆通常分为新生代和老年代。新生代里又会拆为 Eden、From Survivor、To Survivor,绝大多数朝生夕死对象会在这里被 Minor GC 清掉。
    • JDK 8 把永久代改成元空间后,类元数据不再吃 JVM 堆,而是改吃本地内存,这也是为什么类加载过多时常见的是 Metaspace OOM 而不是 PermGen OOM
    • 程序计数器记录当前线程下一条将要执行的字节码指令地址。它几乎不参与面试深挖,但常被问到"哪个区域不会 OOM",答案就是程序计数器。
  • 面试怎么答
    • "堆负责对象,元空间负责类元数据,栈负责方法调用现场。堆和元空间更容易成为线上问题源头,栈更常见的是递归过深导致 StackOverflowError。"
  • 易错点
    • 静态变量本身属于类元数据的一部分,但它引用的对象仍然在堆里。
    • 方法区不是"没有了",而是 HotSpot 的实现从永久代换成了元空间。
对象分配、TLAB 与晋升
  • 核心结论
    • 对象默认优先在 Eden 分配;大对象、长期存活对象会更快进入老年代。
    • TLAB 是线程私有的小块堆内存,作用是降低并发分配时的锁竞争。
  • 原理展开
    • 如果线程先从自己的 TLAB 里切一块内存,就不用每次都去全局争抢 Eden 指针。
    • 大对象直接进老年代是为了避免在新生代频繁复制,但如果大对象很多,会显著增加 Full GC 风险。
    • 对象晋升不是只看年龄阈值,还会看 Survivor 空间占比和动态对象年龄判定。
  • 面试怎么答
    • "HotSpot 对象分配优先 Eden,线程会先走 TLAB,减少分配竞争;如果对象足够大或存活时间长,就会晋升老年代。真正要讲的是这套机制为什么会影响 GC 频率和停顿。"
  • 常见追问
    • 什么是 TLAB?
    • 大对象为什么会直接进老年代?
    • Survivor 区的意义是什么?
方法区、运行时常量池与字符串常量池
  • 核心结论
    • 方法区重点要会区分三件事:类元数据、运行时常量池、字符串常量池的存放位置与版本差异。
  • 原理展开
    • 运行时常量池属于类的一部分,会在类加载后进入方法区相关结构。
    • JDK 7 开始字符串常量池移入堆中,JDK 8 起永久代彻底被元空间替代。
    • 动态代理、字节码增强、频繁热部署等场景都可能不断制造新类,最终打爆元空间。
  • 面试怎么答
    • "方法区要重点区分类元数据和各种常量池,JDK 7/8 的位置变化要能说清。线上常见问题不是概念题,而是动态生成类太多导致元空间膨胀。"
  • 易错点
    • 不能把"运行时常量池"和"字符串常量池"混为一谈。

1.2 直接内存(Direct Memory) ★★

  • 核心结论
    • 直接内存不属于 Java 堆,但会被 JVM 进程消耗,因此也可能把进程打挂。
    • 它常用于 NIO,收益是减少一次堆内拷贝,代价是申请和回收更重。
  • 原理展开
    • DirectByteBuffer 底层通过本地方法申请堆外内存,JVM 只在堆里留一个小对象做引用壳。
    • 如果应用大量创建直接内存而回收不及时,即使堆看起来不大,也可能触发 OutOfMemoryError: Direct buffer memory
    • 直接内存大小可以通过 -XX:MaxDirectMemorySize 控制。
  • 面试怎么答
    • "直接内存的核心价值是提升 IO 性能,尤其在 NIO、Netty、零拷贝链路里常见;但它不受 -Xmx 直接约束,因此线上排障时不能只盯着堆。"
  • 易错点
    • 看到进程内存持续上涨,不代表一定是堆泄漏,也可能是堆外内存吃满。

2. 对象模型 ★★

2.1 对象的创建过程

从类加载检查到 <init>
  • 核心结论
    • 对象创建是一个完整流水线,不是"new 一下就完了"。
  • 原理展开
    • 第一步先做类加载检查,如果类还没加载、解析、初始化,就先触发对应流程。
    • 第二步分配内存。若堆规整可用指针碰撞,不规整则走空闲列表。
    • 第三步把对象实例字段置零值,保证对象拿到后即使还没显式赋值,也有默认状态。
    • 第四步设置对象头,比如 Mark Word、类型指针等。
    • 最后执行构造方法,把程序语义上的初始化补齐。
  • 面试怎么答
    • "对象创建要讲清类加载检查、内存分配、零值初始化、对象头设置和构造方法执行。面试更喜欢追问的是并发下如何保证分配安全,以及 DCL 为什么和对象初始化顺序有关。"
  • 常见追问
    • 指针碰撞和空闲列表分别适用于什么场景?
    • 为什么对象会先分配再执行构造?

2.2 对象内存布局

  • 核心结论
    • HotSpot 对象布局通常可以拆成对象头、实例数据、对齐填充三部分。
  • 原理展开
    • 对象头中的 Mark Word 会承载哈希码、GC 年龄、锁状态等信息,因此它和锁升级、偏向锁等知识是连着的。
    • 如果是数组,对象头里还要多记录数组长度。
    • 对齐填充不是逻辑数据,只是为了满足对象按 8 字节对齐等内存访问要求。
  • 面试怎么答
    • "对象头最值得讲的是 Mark Word,因为它和锁状态、哈希、GC 年龄都有关;数组对象还会多一个长度字段。"
  • 易错点
    • 对象布局不是所有 JVM 都完全一样,回答时最好点名 HotSpot 语境。

2.3 对象访问定位

  • 核心结论
    • JVM 规范不限制对象访问实现,常见有句柄访问和直接指针访问。
    • HotSpot 主要使用直接指针,因此对象引用里通常直接指向对象实例地址。
  • 原理展开
    • 句柄访问的优点是对象移动后只需改句柄,不必改所有引用。
    • 直接指针少一次间接寻址,访问效率更高,因此 HotSpot 更偏向它。
  • 面试怎么答
    • "对象访问主要有句柄和直接指针两种,HotSpot 用直接指针换更高的访问效率。"

3. 垃圾回收(GC) ★★★

3.1 判断对象是否存活

可达性分析与 GC Roots
  • 核心结论
    • 现代 JVM 判断对象是否可回收,核心依据不是引用计数,而是可达性分析。
  • 原理展开
    • 引用计数实现简单,但解决不了循环引用,因此主流 JVM 都不把它作为主要回收依据。
    • GC Roots 常见来源包括虚拟机栈中的引用、方法区中的静态变量和常量引用、JNI 引用、同步锁持有对象等。
    • 只有从 GC Roots 出发不可达的对象,才有资格进入后续回收判定流程。
  • 面试怎么答
    • "JVM 主要靠 GC Roots 做可达性分析。只要对象还能沿着引用链追到根,就不会被回收。这个知识点经常和内存泄漏分析连在一起,因为 MAT 看 retained heap 本质也是在找谁把对象链住了。"
  • 常见追问
    • 为什么不用引用计数?
    • 哪些对象能作为 GC Roots?
四种引用与 finalize()
  • 核心结论
    • 强、软、弱、虚引用的差别,本质是对象被回收的积极程度不同。
    • finalize() 只要知道它不可靠、已经不推荐在新代码里使用即可。
  • 原理展开
    • 软引用更适合做受内存压力影响的缓存。
    • 弱引用下一次 GC 就可能回收,最典型落地就是 ThreadLocalMap 的 key。
    • 虚引用不影响对象生命周期,通常配合 ReferenceQueue 跟踪对象回收时机。
  • 面试怎么答
    • "四种引用要按可回收性回答,不要只背定义。业务里最常见的是软引用缓存、弱引用避免引用链太强、虚引用做资源回收跟踪。"
  • 易错点
    • 软引用不是生产缓存银弹,内存一紧张就会大面积失效。

3.2 垃圾回收算法 ★★★

标记清除、复制、整理
  • 核心结论
    • 三种基础算法没有绝对优劣,关键在于适用代和取舍。
  • 原理展开
    • 标记清除实现简单,但会产生内存碎片。
    • 标记复制适合对象存活率低的区域,所以新生代很常用。
    • 标记整理适合老年代,避免碎片但对象移动成本更高。
    • 分代收集理论建立在"大部分对象朝生夕死、少数对象长期存活、跨代引用相对少"这些经验假设上。
  • 面试怎么答
    • "新生代适合复制,老年代更常见清除或整理。回答算法时最好顺手把为什么分代一起讲掉。"
  • 易错点
    • 不要把 Minor GC、Major GC、Full GC 和某种单一算法机械绑定。

3.3 垃圾收集器 ★★★

CMS vs G1
  • 核心结论
    • 面试里最常问的不是收集器全家桶,而是 CMS 和 G1 的设计差异、适用场景与调优思路。
  • 原理展开
    • CMS 追求低停顿,老年代采用标记清除,会有碎片和浮动垃圾问题。
    • G1 把堆拆成 Region,按回收收益优先回收,目标是更可预测的停顿控制。
    • G1 的 Remembered Set、写屏障、Mixed GC 是高频追问点。
  • 面试怎么答
    • "CMS 的核心问题是碎片和 Concurrent Mode Failure,G1 的核心价值是把整堆切成 Region,以收益优先方式回收,适合更大堆和更稳定的停顿目标。"
  • 常见追问
    • Mixed GC 是什么?
    • G1 为什么不需要传统物理分代连续空间?
    • G1 什么时候会退化成 Full GC?
ZGC 与前沿收集器
  • 核心结论
    • ZGC 和 Shenandoah 更像加分题,重点是知道它们为什么停顿短,而不是背完整实现。
  • 原理展开
    • ZGC 通过染色指针、读屏障、并发移动对象,把大部分回收工作和业务线程并行化。
    • 它更适合超大堆和低延迟场景,但配置、版本和运维经验要求更高。
  • 面试怎么答
    • "如果业务核心目标是超大堆下的极低停顿,ZGC 是值得考虑的;但生产选型不能只看前沿,要看团队是否能驾驭。"

3.4 GC调优实战 ★★★

调优目标、指标与常用参数
  • 核心结论
    • GC 调优不是调参数比赛,第一步永远是明确目标:吞吐量优先还是停顿优先。
  • 原理展开
    • 常见观测指标包括 Young GC 频率、Full GC 次数、单次停顿时间、晋升速率、对象分配速率、老年代占用变化等。
    • 常见参数包括 -Xms-Xmx-Xss-XX:MaxMetaspaceSize-XX:+UseG1GC-Xlog:gc*-XX:+HeapDumpOnOutOfMemoryError
    • 调优一般遵循"先日志、再归因、再小步调整、最后对比验证"。
  • 面试怎么答
    • "我会先打开 GC 日志,确认是年轻代过于频繁、老年代回收不及时,还是元空间异常增长,然后再决定是调堆大小、分代比例,还是直接换收集器。"
  • 易错点
    • 没有日志和数据支撑,只说"调大内存"通常是低质量答案。
一套可复用的 GC 排查链路
  • 回答框架
    • 先确认现象:是 RT 抖动、Full GC 频繁,还是 OOM。
    • 再用工具:GC 日志、jstatjmap、Arthas、监控平台。
    • 然后做归因:分配过快、缓存打爆、线程池堆积、类加载异常,还是直接内存问题。
    • 最后做动作:参数调整、代码修复、对象生命周期优化、缓存治理或容量扩容。

4. 类加载机制 ★★★

4.1 类加载过程

加载、验证、准备、解析、初始化
  • 核心结论
    • 类加载过程本质上是把字节码变成 JVM 可执行结构,并在真正需要时完成初始化。
  • 原理展开
    • 加载阶段把字节码读进来并创建对应的 Class 对象。
    • 准备阶段为类变量分配内存并赋零值,初始化阶段才真正执行 <clinit>
    • static final 编译期常量在很多场景下会被直接内联,这也是为什么某些访问不会触发类初始化。
  • 面试怎么答
    • "类加载五步里最容易被追问的是准备和初始化的区别,以及哪些主动使用会触发初始化。"
  • 常见追问
    • 访问 static final 常量会触发初始化吗?
    • 子类初始化前父类是否会先初始化?

4.2 类加载器 ★★★

  • 核心结论
    • 类加载器回答要抓住三层:Bootstrap、Platform、Application,再补一个自定义加载器的意义。
  • 原理展开
    • 自定义 ClassLoader 常见于热部署、插件化、隔离不同模块依赖等场景。
    • 类在 JVM 中的唯一性由"类加载器 + 类全名"共同决定,因此同名类被不同加载器加载后可以互不兼容。
  • 面试怎么答
    • "类加载器不仅决定加载路径,也决定类隔离边界。Tomcat、OSGi、SPI 这些场景本质上都在玩类加载边界。"

4.3 双亲委派模型 ★★★

为什么要有双亲委派,为什么有时又要打破
  • 核心结论
    • 双亲委派的价值是避免核心类被重复加载,保证基础类库的安全性和一致性。
  • 原理展开
    • 正常情况下,子加载器先把加载请求往上交,只有父加载器找不到时才自己加载。
    • SPI、Tomcat、多模块隔离这些场景打破双亲委派,是因为"基础类要反过来调用业务实现"或"不同应用要隔离同名依赖"。
  • 面试怎么答
    • "双亲委派默认解决安全和一致性问题,但在 SPI、容器隔离等需要反向查找实现类的场景里,必须有意打破。"
  • 易错点
    • 打破双亲委派不是把整个机制推翻,而是针对特定加载链路做局部调整。

5. JIT编译与执行引擎 ★★

5.1 解释执行 vs 编译执行

  • 核心结论
    • JVM 不是纯解释器,也不是纯编译器,而是解释执行和 JIT 编译并存的混合模式。
  • 原理展开
    • 热点代码会被编译成本地机器码,减少重复解释开销。
    • 分层编译会让 JVM 在启动速度和峰值性能之间做动态平衡。
  • 面试怎么答
    • "JVM 通过解释 + JIT 的混合模式兼顾启动和运行性能,热点代码才值得被重点优化。"

5.2 JIT优化技术

  • 核心结论
    • JIT 重点记住方法内联、逃逸分析、锁消除、标量替换这些高频点。
  • 原理展开
    • 如果对象没有逃出方法或线程,就可能被栈上分配或者直接被拆成若干标量。
    • 锁消除建立在逃逸分析基础上,因此不是所有同步块都一定要付出同样成本。
  • 面试怎么答
    • "JIT 真正做的是把热点路径里的抽象成本抹平,比如内联调用、消掉不必要锁、减少堆分配。"

6. 线上问题排查工具 ★★★

6.1 JDK自带工具

  • 核心结论
    • 面试里最值钱的不是把命令都背一遍,而是能把命令串成一条排障路径。
  • 推荐掌握
    • jps:先找到 Java 进程。
    • jstat:看 GC 行为和分代使用情况。
    • jmap:看对象分布、导出堆快照。
    • jstack:看线程状态、死锁、阻塞栈。
    • jcmd:统一入口,很多场景比老命令更顺手。

6.2 可视化工具

  • 核心结论
    • JVisualVM、JConsole、MAT、GCEasy 这类工具主要价值是提升分析效率。
  • 使用建议
    • 堆泄漏排查优先 MAT。
    • GC 日志分析优先 GCEasy / GCViewer。
    • 临时观测进程资源可先用 JVisualVM 快速确认趋势。

6.3 Arthas ★★★(阿里开源,面试加分)

为什么 Arthas 常被当作线上排障利器
  • 核心结论
    • Arthas 的价值在于不停机、少侵入、线上即连即看。
  • 重点命令
    • dashboard:先看整体概况。
    • thread:看 CPU 最高线程和阻塞线程。
    • watch / trace:定位方法耗时和参数。
    • sc / sm:查类、查方法。
    • heapdump:必要时导出堆快照。
  • 面试怎么答
    • "线上先用 dashboard 和 thread 定位方向,再对可疑方法用 trace/watch 精确下钻。Arthas 的优势是不用重启、不改代码。"

二、高频面试题

基础级(P7必答)

  1. JVM 内存结构?堆是如何分代的?
  • 30秒答法:JVM 里最关键的区域是堆、元空间和线程栈。堆是对象和数组的主要落点,通常分新生代和老年代;新生代再分 Eden 和两个 Survivor,用于让短命对象尽快被 Minor GC 回收。
  • 关键词:堆、新生代、老年代、Survivor、元空间、栈帧
  • 追问提醒:JDK 8 元空间替代永久代;对象晋升条件;程序计数器为什么不会 OOM
  1. 如何判断对象可以被回收?GC Roots 有哪些?
  • 30秒答法:主流 JVM 通过可达性分析判断对象是否存活。只要对象还能从 GC Roots 沿引用链走到,就不会被回收;Roots 常见来源包括虚拟机栈引用、静态变量、常量和 JNI 引用。
  • 关键词:可达性分析、GC Roots、引用链、静态变量、JNI
  • 追问提醒:为什么不用引用计数;四种引用;finalize() 为什么不推荐
  1. CMS 和 G1 的区别?各自适用什么场景?
  • 30秒答法:CMS 追求低停顿,老年代采用标记清除,问题是碎片和浮动垃圾;G1 按 Region 管理整堆,以回收收益优先控制停顿,更适合大堆和更稳定的停顿目标。
  • 关键词:CMS、G1、Region、Mixed GC、碎片、停顿预测
  • 追问提醒:Remembered Set;G1 什么时候 Full GC;为什么 CMS 会 Concurrent Mode Failure
  1. 什么情况下会发生 Full GC?如何减少 Full GC?
  • 30秒答法:老年代空间不足、元空间不足、显式 System.gc()、收集器退化都可能触发 Full GC。减少的思路是先确认根因,再决定是优化对象生命周期、调整堆/元空间、控制大对象,还是更换收集器。
  • 关键词:Full GC、老年代、元空间、System.gc()、退化
  • 追问提醒:Minor/Major/Full 区别;GC 日志怎么分析;类加载过多如何处理
  1. 双亲委派模型是什么?为什么有时要打破?
  • 30秒答法:双亲委派是子加载器先把请求交给父加载器,父找不到再自己加载,目的是保证核心类安全和避免重复加载。SPI、Tomcat 隔离、多模块插件场景会局部打破它。
  • 关键词:双亲委派、类加载器、SPI、Tomcat、隔离
  • 追问提醒:类唯一性为什么是"加载器 + 类名";线程上下文类加载器的作用
  1. JDK 7 和 8 在内存结构上有什么变化?
  • 30秒答法:JDK 7 把字符串常量池移到了堆里;JDK 8 彻底去掉永久代,引入元空间,类元数据改用本地内存,缓解固定大小永久代容易 OOM 的问题。
  • 关键词:永久代、元空间、字符串常量池、本地内存
  • 追问提醒:Metaspace OOM 场景;动态代理、热部署、脚本引擎
  1. 强引用、软引用、弱引用、虚引用的区别和应用场景?
  • 30秒答法:区别在对象被 GC 回收的积极程度。强引用不回收,软引用在内存紧张时回收,弱引用下次 GC 基本就会被清,虚引用主要配合队列跟踪回收事件。
  • 关键词:强软弱虚、ReferenceQueue、缓存、ThreadLocalMap
  • 追问提醒:软引用为什么不适合作为稳定缓存;弱引用在框架里的典型应用
  1. 什么是 STW?如何减少停顿时间?
  • 30秒答法:Stop The World 指 GC 等安全点操作期间暂停所有业务线程。减少停顿通常靠选择更合适的收集器、控制堆大小、降低分配速率、避免频繁 Full GC。
  • 关键词:STW、停顿时间、G1、ZGC、分配速率
  • 追问提醒:安全点和安全区域;为什么不可能完全没有停顿
  1. 对象分配过程是什么?大对象如何处理?
  • 30秒答法:对象创建会经历类加载检查、内存分配、零值初始化、对象头设置和构造方法执行。大对象通常会直接进入老年代,避免在新生代频繁复制,但会加剧老年代压力。
  • 关键词:TLAB、Eden、大对象、老年代、对象头
  • 追问提醒:指针碰撞和空闲列表;对象晋升规则
  1. jstackjmap、MAT 分别怎么用?
  • 30秒答法:jstack 看线程栈和死锁,jmap 看对象分布或导出堆快照,MAT 用来分析 dump 后谁占内存、谁链住对象。三者串起来就是典型的线程与内存问题排障链路。
  • 关键词:线程 dump、heap dump、Histogram、Dominator Tree
  • 追问提醒:CPU 100% 怎么从 top -Hp 接到 jstack;堆泄漏怎么看 retained heap

进阶级(P8+深挖)

  1. G1 的 Mixed GC 是怎么工作的?
  • 30秒答法:G1 先通过并发标记识别老年代里回收价值高的 Region,再在 Young GC 基础上混合回收这些老年代 Region。它的核心不是"每次都回收整个老年代",而是按收益挑选。
  • 关键词:并发标记、Region、Mixed GC、回收收益
  • 追问提醒:Remembered Set;写屏障;Humongous Region
  1. ZGC 为什么能做到低停顿?
  • 30秒答法:ZGC 通过染色指针和读屏障,把对象移动和大部分标记工作与应用线程并发执行,真正 STW 的阶段被压得很短,所以适合大堆低延迟。
  • 关键词:染色指针、读屏障、并发移动、低停顿
  • 追问提醒:和 G1 的取舍;生产版本与运维成本
  1. 你在生产环境里通常怎么做 GC 调优?
  • 30秒答法:先收集 GC 日志和监控指标,确认问题是 Young GC 过频、Full GC 过多,还是停顿过长;再结合对象分配速率、老年代增长、元空间变化做归因,最后用小步参数调整和灰度验证对比效果。
  • 关键词:GC 日志、分配速率、晋升速率、灰度验证
  • 追问提醒:如何证明调优有效;吞吐量和停顿优先怎么权衡
  1. 逃逸分析在实际项目里有什么价值?
  • 30秒答法:逃逸分析能帮助 JVM 做栈上分配、标量替换和锁消除,本质是减少堆分配和同步开销。它通常不是手工优化主线,但理解它有助于解释为什么某些对象和锁没有想象中那么贵。
  • 关键词:逃逸分析、锁消除、标量替换、栈上分配
  • 追问提醒:怎么验证是否触发;JMH 和 JITWatch 的用途
  1. Metaspace OOM 常见于哪些场景?怎么排查?
  • 30秒答法:动态代理、脚本执行、频繁热部署、大量生成类都可能导致元空间膨胀。排查时要看类加载数量、类加载器分布和是否存在不能卸载的 ClassLoader 引用链。
  • 关键词:Metaspace OOM、ClassLoader、动态代理、热部署
  • 追问提醒:为什么类卸载困难;如何限制元空间上限

三、实战场景题(P8+重点)

  1. 线上 Full GC 频繁,接口 RT 明显抖动
  • 回答框架
    • 先看现象:确认 Full GC 的频率、停顿时长、业务影响面。
    • 再看数据:GC 日志、jstat、堆使用趋势、对象分配速率、老年代增长速度。
    • 再做归因:是缓存打满、大对象过多、对象晋升过快、元空间问题,还是收集器选型不合适。
    • 最后落动作:代码修复、参数调整、容量扩容、缓存治理,做灰度和效果对比。
  • 核心关注点:不能一上来就说"调大堆";要先定位根因。
  1. 服务运行一段时间后 OOM,怀疑内存泄漏
  • 回答框架
    • 先确认是堆、元空间还是直接内存 OOM。
    • 对堆问题导出 dump,用 MAT 看 Histogram、Dominator Tree、GC Roots 链路。
    • 结合业务代码判断是缓存未清、集合持有、线程池任务积压,还是 ThreadLocal、监听器等未释放。
    • 修复后补监控和压测,验证泄漏是否真正消失。
  • 核心关注点:定位要落到"谁持有了它",而不是只说某个对象很多。
  1. Java 进程 CPU 100%,如何快速定位?
  • 回答框架
    • top 找进程,top -Hp 找高 CPU 线程。
    • 线程 ID 转十六进制后用 jstack 对应到具体栈。
    • 判断是死循环、频繁 GC、锁竞争、热点方法,还是 JIT 编译期波动。
    • 必要时用 Arthas threadtrace 精细下钻。
  • 核心关注点:要把 Linux 命令和 JVM 工具连成闭环。
  1. 类加载异常增长,怀疑代理类或热部署问题
  • 回答框架
    • 先看类加载总数与趋势。
    • 再看是否有异常增多的 ClassLoader。
    • 判断是否存在重复创建代理、脚本反复编译、旧 ClassLoader 被强引用导致无法卸载。
    • 最后做代码和部署治理,比如复用代理、清理引用链、规范热更新机制。
  • 核心关注点:类无法卸载,往往不是类本身的问题,而是 ClassLoader 被链住了。

四、学习资源推荐

书籍

  • 《深入理解Java虚拟机》:JVM 面试和原理的主教材
  • 《Java Performance》:偏实践,适合把 GC、JIT、性能排查串起来
  • 《垃圾回收的算法与实现》:想继续深挖 GC 原理时再看

博客/文章

  • 美团技术团队 JVM 系列文章:偏实战,适合把 GC 和排障结合起来
  • 阿里 Arthas 官方文档:线上排障命令的最好参考
  • OpenJDK 官方文档:查收集器、参数和版本差异最可靠

视频

  • 极客时间 JVM 专题课程:适合建立整体系
  • B站 JVM GC 日志分析实战:适合做调参和排障补充

On this page