JVM垃圾回收与JIT编译:finalize、引用计数、GC算法、即时编译器全解析(2026版) ⚙️第42篇JVM垃圾回收与JIT编译finalize、引用计数、GC算法、即时编译器全解析2026版系列导航《Java 100 天进阶之路》完整目录 |⬅️ 上一篇第41篇GET和POST的区别、堆和栈的区别 |➡️ 下一篇第43篇Java字节码javap命令解读字节码清单一、核心知识点finalize()方法已弃用GC 前调用执行时机不确定不推荐使用引用计数法JVM 不使用循环引用问题JVM 垃圾回收算法复制算法年轻代标记-清除老年代标记-整理老年代JITJust-In-Time即时编译器热点代码编译为机器码提高性能其他相关概念对象复活、GC Roots、Stop-The-World、JVM 参数调优二、通俗讲解1分钟开心学1. finalize——已过时的“遗言”finalize()是Object类的一个方法垃圾回收器在回收对象前会调用它。你可以覆盖它来做一些清理比如关闭文件。但它的执行时机不确定不知道什么时候被回收而且可能导致对象“复活”重新被引用性能也差。从 Java 9 开始已弃用。推荐使用try-with-resources或Cleaner。生活类比finalize()就像临终遗言但不确定什么时候念还可能被人救活复活所以不靠谱。现代 Java 直接用try-with-resources自动关闭资源就像离开房间自动关灯安全可靠。2. 引用计数法JVM 为什么不使用每个对象记录被引用的次数次数为零时回收。简单但无法处理循环引用A 引用 BB 引用 A外部没有引用它们但计数为 1永远不会回收。JVM 使用可达性分析算法GC Roots来代替。3. JVM 垃圾回收算法对比算法原理优点缺点适用区域复制算法内存分为两块只用一块存活对象复制到另一块清空原区域无碎片简单高效内存利用率低只用一半年轻代对象存活率低标记-清除标记存活对象清除未标记的无需移动对象产生内存碎片效率随对象增多下降老年代CMS 回收器标记-整理标记后将存活对象向一端移动清理边界外内存无碎片移动对象开销大需 Stop-The-World老年代Serial Old、Parallel Old4. JIT 即时编译器Java 程序开始运行时字节码由解释器执行。JVM 会检测“热点代码”频繁执行的方法或循环将其编译成本地机器码编译后直接执行不再解释。这能大幅提升性能尤其是长期运行的应用。生活类比JIT 就像你每天通勤走同样的路线走几次后你不再查地图解释执行而是凭记忆快速走过去编译优化。finalize就像临终遗言但不确定什么时候念还可能被人救活复活所以不靠谱。三、实操代码案例 场景说明finalize 示例不推荐仅用于理解classResource{Overrideprotectedvoidfinalize()throwsThrowable{System.out.println(资源被回收了);super.finalize();}}publicclassFinalizeDemo{publicstaticvoidmain(String[]args){for(inti0;i1000;i){newResource();}System.gc();// 建议 GC但不保证立即执行try{Thread.sleep(100);}catch(InterruptedExceptione){}}}对象复活示例了解即可不要这样写publicclassResurrection{publicstaticResurrectioninstancenull;Overrideprotectedvoidfinalize(){System.out.println(finalize 执行对象复活);instancethis;}publicstaticvoidmain(String[]args)throwsException{instancenewResurrection();instancenull;System.gc();Thread.sleep(100);System.out.println(instance);// 不为 null复活成功}}JIT 效果示意publicclassJITDemo{publicstaticvoidmain(String[]args){longstartSystem.nanoTime();intsum0;for(inti0;i100_000_000;i){sumi;}longendSystem.nanoTime();System.out.println(耗时(end-start)/1e6 ms);// 多次运行会发现第二次开始明显变快JIT 已优化}}四、避坑要点高频踩坑汇总错误/误区后果正确做法依赖finalize()释放资源资源泄漏因为不知道何时调用使用try-with-resources或Cleaner认为引用计数法适合 Java无法解决循环引用JVM 用可达性分析GC Roots担心 JIT 编译会浪费启动时间过度优化JIT 对长期运行的应用非常有益手动调用System.gc()不一定会立即 GC且影响性能让 JVM 自动管理误以为finalize()只会执行一次对象复活后可再次被回收finalize()不会重复执行了解即可实际不要用混淆年轻代和老年代的 GC 算法选错回收器导致性能问题年轻代用复制算法老年代用标记-清除或标记-整理认为 JIT 编译所有代码只编译热点代码了解 JIT 触发条件方法调用次数、循环次数阈值五、面试高频考点附详细答案Q1为什么 JVM 不用引用计数法无法解决循环引用问题如 A 引用 BB 引用 A外部无引用但计数不为 0且每个对象都需要维护计数器有额外开销。JVM 使用可达性分析GC Roots代替。Q2年轻代和老年代各自使用什么 GC 算法年轻代复制算法Eden Survivor 空间因为对象存活率低。老年代标记-清除如 CMS或标记-整理如 Serial Old、G1 的部分行为因为对象存活率高需要减少移动。Q3JIT 编译器的作用是什么将热点字节码编译成本地机器码提高执行效率。与 AOT提前编译相比JIT 可根据运行时信息做更激进的优化如内联、逃逸分析。Q4finalize()方法有什么问题执行时机不确定依赖 GC可能导致对象复活性能差且容易引发资源泄漏。Java 9 起已标记为弃用。Q5什么是 Stop-The-World哪些情况会发生Stop-The-World 是指 JVM 暂停所有应用线程只让 GC 线程工作。发生在 GC 的某些阶段如标记、整理、复制G1、ZGC 等回收器努力减少 STW 时间。Q6如何判断一个对象是否可回收通过可达性分析从 GC Roots如栈帧中的局部变量、静态变量、JNI 引用等出发无法到达的对象即不可达可被回收。Q7GC Roots 包括哪些包括虚拟机栈栈帧中的局部变量引用的对象、方法区中静态属性引用的对象、方法区中常量引用的对象、本地方法栈中 JNI 引用的对象、活跃线程等。Q8JIT 编译的触发条件是什么方法调用计数器默认 10000 次或循环回边计数器达到阈值触发 C1快速编译或 C2优化编译。可通过-XX:CompileThreshold调整。六、练习题简答复制算法的优点和缺点。代码分析为什么finalize()可以被调用多次复活如何避免动手写一个程序让 JIT 编译一个热点方法可以通过-XX:PrintCompilation观察编译日志。思考如果老年代也使用复制算法会有什么问题排查如何查看 JVM 默认的垃圾回收器 你的学习进度当前第42篇 / 共44篇 ·第六阶段NIO、泛型、JVM内幕、字节码第36~44篇✅ 已完成第1~41篇 正在学第42篇⏳ 待学习第43~44篇 完整目录 学习指南 | 订阅本专栏不错过每一篇 本专栏每篇都包含避坑表 面试高频考点 练习题。每天30分钟100天拿offer 下一篇文章预告《第43篇Java字节码javap命令解读字节码清单》内容简介字节码作用、javap命令、常见字节码指令、通过字节码看语法糖。 学完这篇你将能读懂.class文件理解JVM执行原理。《Java 100 天进阶之路 | 从入门到上岗就业》每天一篇建议收藏 关注一起100天拿offer 点击关注我更新后第一时间收到推送 除了《Java 100 天进阶之路 | 从入门到上岗就业》系列文章我也在深挖智能物流实战出版社WMS、托盘调度、机器学习落地。如果你对技术在不同领域的实战感兴趣欢迎点击我的头像看看专栏《出版社物流WMS智能调度实战》。技术相通思路可鉴。