Java 堆存放所有對象實例,由 new、newarray 等指令分配。與 C++ 手動 delete 不同,Java 採用自動內存管理:垃圾收集器(GC)識別並回收無引用對象,釋放內存供新對象使用。這不僅提高開發效率,更是 Java 安全性策略的核心組成部分——防止內存洩漏、懸空指針等底層漏洞。
| 優勢 | 劣勢 |
|---|---|
| 自動釋放無用對象,消除手動內存管理負擔 | GC 過程消耗 CPU 時間,影響應用吞吐量 |
| 內存碎片整理,提升分配效率 | 早期算法無法 100% 回收所有垃圾(現已大幅改善) |
| 保護程序完整性,構建安全沙箱基礎 | 停頓時間(Stop-the-World)可能影響實時響應 |
每個對象維護計數器,引用+1,失效-1,歸零即回收。
優點:增量式回收,無長停頓。
缺點:無法處理循環引用;每次賦值需更新計數器,開銷大。
現狀:主流 JVM(HotSpot)未採用。
從 GC Roots(棧帧局部變量、靜態字段、JNI 引用等)出發,標記可達對象,未標記者為垃圾。
兩階段:Mark(標記)+ Sweep(清除)。
缺點:產生內存碎片;需遍歷整個堆。
在清除階段將存活對象向一端移動,消除碎片,更新引用地址。
代價:移動對象需更新所有引用,耗時較長。
將堆劃分為 From/To 兩塊,每次僅使用 From,GC 時將存活對象複製到 To,角色互換。
優點:無碎片,分配指針碰撞極快。
缺點:內存利用率仅 50%;存活對象多時複製開銷大。
應用:新生代(Eden + Survivor)。
核心假設:「多數對象朝生夕死,少數對象長期存活。」
堆劃分:新生代(Young Gen)+ 老年代(Old Gen)。
流程:
運行時監控堆狀態,動態選擇最優策略(如 G1、ZGC 的混合模式)。
java -verbose:gc -Xlog:gc*:file=gc.log -XX:+PrintGCDetails -XX:+PrintGCTimeStamps MyApp
關鍵指標解讀:
[Full GC 168K->97K(1984K), 0.025s]:GC 前後存活內存、堆總大小、耗時protected void finalize() throws Throwable 在對象被回收前調用,用於釋放非 Java 資源(如 JNI 分配的內存、文件句柄)。
⚠️ 關鍵警示:
try-with-resources、Cleaner (Java 9+)、PhantomReferencenull、移除監聽器、清理 ThreadLocalJava GC 從簡單的標記-清除演進為高度優化的分代、並發、自適應系統。開發者無需掌握所有底層細節,但必須理解:內存管理是契約,而非魔法。理解對象生命周期、引用鏈路、GC 分代假設,配合合理的 JVM 參數與編碼規範,才能構建穩定高效的 Java 應用。隨著 ZGC、Shenandoah 等低延遲收集器成熟,GC 停頓已不再是高併發系統的瓶頸——前提是你不製造「垃圾山」。