首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 垃圾收集算法深度解析與調優指南

     編輯:Java 相關知識

1. GC 核心思想

Java 通過可達性分析識別存活對象:從 GC Roots(棧局部變量、靜態字段、JNI 引用等)出發,能到達的對象為存活對象,不可達的為垃圾對象,回收其內存。
核心目標:防止內存耗盡、避免非法引用。

2. 主 GC (Major GC/Full GC) 觸發條件

  • 應用空閒時:GC 線程優先級最低,僅在無用戶線程運行時工作。
  • 堆內存不足:分配新對象時空間不夠,JVM 強制觸發 GC。若連續 3 次 GC 仍不足,拋出 OutOfMemoryError。

主 GC 具有不確定性,長期運行應用會反復觸發。

3. 減少 GC 開銷的 7 大措施

  1. 別顯式調 System.gc():只是建議,可能觸發 Full GC,增加停頓。
  2. 減少臨時對象:少創建短命對象,延長 Minor GC 間隔。
  3. 不用對象置 null:幫助 GC 更快識別垃圾(局部變量無需,出作用域自動清除)。
  4. 用 StringBuilder 代替 String 累加:避免產生大量中間字符串對象。
  5. 優先用基本類型:int 比 Integer 省內存、無對象頭開銷。
  6. 少用靜態字段引用大對象:靜態字段屬於 GC Root,永不回收。
  7. 分散對象創建/銷毀時間:避免瞬間大量分配觸發 Full GC,或瞬間大量釋放導致下次分配觸發 GC。

4. gc() 與 finalize()

System.gc()

請求 JVM 執行 GC,非強制。JVM 會對多種算法加權,使 GC「更容易、更早、回收更多」。

finalize()

對象被回收前調用,原型:protected void finalize() throws Throwable。
用途:釋放非內存資源(文件句柄、連接等)。
缺點:調用時機不確定、異常會被吞噬、拖慢 GC。現代開發推薦 try-with-resources / AutoCloseable。

class Garbage {
    static int count;
    int id;
    Garbage() { System.out.println("construct " + (++count)); id = count; }
    protected void finalize() { System.out.println("reclaim " + id); }
    public static void main(String[] args) {
        new Garbage(); new Garbage(); new Garbage(); new Garbage();
        System.gc(); // 請求 GC
    }
}

5. Java 內存洩漏本質

非傳統意義的「內存未釋放」,而是無意識持有對象引用,導致本可回收對象長期駐留堆中。

經典案例:棧實現未清理數組引用

public Object pop() {
    index--;
    return stack[index]; // 數組仍持有引用!
}
// 正確:
public Object pop() {
    Object obj = stack[--index];
    stack[index] = null; // 斷開引用
    return obj;
}

常見洩漏源

  • 全局集合/緩存無清理策略:需定期清理或用 SoftReference、WeakHashMap、LinkedHashMap (LRU)。
  • 監聽器/回調未移除:註冊後忘記 removeListener。
  • ClassLoader 洩漏:靜態字段持有類/類加載器引用,熱部署時導致元空間洩漏。

6. 洩漏排查思路

  1. 觀察 OutOfMemoryError 或 GC 頻率/耗時異常。
  2. 持續監控 GC 日誌(-Xlog:gc*),確認老年代佔用持續上升。
  3. 使用工具:jmap -histo、jhat、Arthas、MAT (Eclipse Memory Analyzer)、JProfiler、Async Profiler。
  4. 定位支配者樹,找到阻礙回收的 GC Root 鏈路。

總結

理解可達性分析、分代假設、GC 觸發條件是調優基石。良好編碼習慣(少臨時對象、斷開引用、用基本類型、緩存加上限)能解決 90% 問題。複雜洩漏需工具輔助分析,MAT + Arthas 是現代最佳組合。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved