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

撰寫 GC 友好且無記憶體洩漏的 Java 代碼實戰指南

     編輯:J2EE

一、擁抱短生命週期、小物件、不可變物件

  • 現代 JVM (HotSpot) 在新生代分配物件極快(約 10 條 CPU 指令),GC 掃描存活物件成本遠低於掃描整個堆。
  • 大物件易造成記憶體碎片,特別是非壓縮 GC 算法下。
  • 物件重用增加代碼複雜度、降低可讀性,反而不利 JIT 優化。
  • 建議: 大膽為中間結果建立小物件,善用不可變類別(String、LocalDate、Guava 不可變集合)。

二、將用完的參考設為 null 幾乎無效

  • JIT 編譯器會自動分析區域變數生命週期,方法結束前手動 obj = null 多此一舉。
  • 例外:陣列元素(如 String[1024] arr; arr[100] = null;)需手動釋放,否則整個陣列保持可達。最佳做法:直接用 ArrayList 等標準集合。

三、避免顯式呼叫 System.gc()

  • Full GC 代價極大,時機把握困難,甚至有 -XX:+DisableExplicitGC 參數禁止。
  • 第三方庫(如 RMI、EJB 底層的 RMI)可能內部呼叫 System.gc()。
  • 緩解參數:-Dsun.rmi.dgc.client.gcInterval=3600000 -Dsun.rmi.dgc.server.gcInterval=3600000(單位微秒,調大間隔);-XX:+ExplicitGCInvokesConcurrent 讓顯式 GC 走 CMS 並發路徑。

四、finalize() 是效能殺手

  • 分配成本高、釋放更高(需額外 GC 週期)、調用時間不確定、JVM 關閉時不再執行、順序不定。
  • 堅決不用。 資源釋放請用 try-with-resources 或 finally 區塊顯式關閉。

五、善用 WeakReference / SoftReference

  • WeakReference: 不阻止 GC,適合快取鍵值對、監聽器註冊(避免記憶體洩漏)。
  • SoftReference: 記憶體充足時保留,不足時回收,極適合實作簡易快取。
  • ReferenceQueue: 物件被回收時入隊,可接收通知執行清理邏輯,優於 finalize()。

六、Java 記憶體洩漏真相與排查

洩漏定義: 物件對應用已無用,但因被長生命週期物件持有而持續可達,無法被 GC 回收。

常見原因對策
長壽命集合(Map/List/快取)未清理用 WeakHashMap、定期清理、或 WeakReference 包裝值
變數作用域定義錯誤(局部變成欄位/靜態)嚴格限制變數作用域,盡量用局部變數
異常路徑未在 finally 釋放資源(JDBC 連線、流)全面採用 try-with-resources
Swing 監聽器未移除、內部類隱含外部參考、Finalizer 延遲釋放關聯物件明確移除監聽器、靜態內部類+弱參考、避免 finalize

七、JDK 內建工具快速定位洩漏

  1. jps 找進程 ID。
  2. jmap -histo pid 查看類別實例數與佔用大小;jmap -dump:file=heap.bin pid 導出堆快照。
  3. jhat heap.bin 啟動分析伺服器,瀏覽器開 https://localhost:7000/ 追蹤 GC Roots 保留路徑。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved