垃圾:不再被任何引用指向的物件。
GC (Garbage Collector):JVM 守護線程,依演算法自動回收垃圾、整理記憶體碎片。
public class Demo {
public static void main(String[] args) {
new Demo(); // 無引用,理論上可回收
System.gc(); // 通知 GC
System.out.println("over!");
}
@Override
protected void finalize() throws Throwable {
System.out.println("垃圾回收前的工作!");
super.finalize();
}
}
可能輸出:over!(無 finalize 輸出)
原因:JVM 記憶體充足時,GC 可能不執行;System.gc() 只是建議,非強制。
同樣代碼,若 JVM 閒置,可能輸出:
over! 垃圾回收前的工作!
或反序。說明 GC 執行具有非確定性。
鐵律:絕不可依賴 finalize() 釋放關鍵資源。請使用
try-with-resources、AutoCloseable、Cleaner(JDK 9+) 或顯式close()。
System.gc()、Runtime.getRuntime().gc()(僅建議)| 原則 | 具體做法 | 效果 |
|---|---|---|
| 不製造垃圾 | 減少臨時物件、物件復用、StringBuilder 替代 + 拼接 | 降低分配率、減少 Minor GC 頻率 |
| 不主動請求 GC | 禁止呼叫 System.gc(),依賴 JVM 自適應調節 | 避免干擾 GC 節奏、防止 Full GC 風暴 |
| 明確生命週期 | 用完即置 null、try-with-resources、ThreadLocal remove() | 縮短物件存活期、助推新生代回收 |
| 避免集中分配 | 批次處理分批、流式處理替代全量載入 | 平滑分配曲線、減少晋升失敗 |
| 嚴謹防洩漏 | 靜態集合清理、監聽器移除、快取淘汰策略 | 根治 OOM、保護老年代 |
# JVM 參數範例(JDK 8)
-Xms4g -Xmx4g -Xmn2g
-XX:+UseConcMarkSweepGC -XX:+UseParNewGC
-XX:+PrintGCDetails -XX:+PrintGCDateStamps
-Xloggc:/logs/gc-%t.log -XX:+UseGCLogFileRotation
-XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=100M
關鍵指標:
| 現象 | 可能原因 | 解決方向 |
|---|---|---|
| 頻繁 Minor GC | 新生代過小、大量短命物件 | 增大 -Xmn、優化分配率、物件復用 |
| 頻繁 Full GC | 老年代洩漏、大物件直入老年代、System.gc() | MAT 分析堆轉儲、調大老年代、移除手動 GC |
| GC 停頓過長 | CMS 碎片整理、G1 混合回收不及時、大物件 | 調優 CMS/G1 參數、避免大物件、考慮 ZGC/Shenandoah |
| Metaspace OOM | 類加載過多(動態代理、JSP、Groovy)、類洩漏 | 限制 MaxMetaspaceSize、排查動態生成類 |
總結:GC 是 JVM 自動記憶體管理的基石。理解其觸發機制、演算法特性、日誌分析方法,並遵循「少分配、短生命、不干預」原則,是構建高效能、穩定 Java 應用的核心功力。