Java 的一大優勢是通過垃圾收集器(GC)自動管理內存回收,許多開發者誤以為 Java 不存在內存洩漏,或認為洩漏非程式責任。實則不然,Java 同樣存在內存洩漏,只是表現形式與 C++ 不同。隨著服務器端程式(JSP、Servlet、EJB 等)長期運行,以及嵌入式系統內存受限,即使微量洩漏積累久了也會導致系統崩潰,內存洩漏問題不容忽視。
Java 內存管理核心是對象分配與釋放。程式通過 new 在堆中分配對象空間,釋放由 GC 自動完成。GC 需監控對象全生命週期狀態(申請、引用、賦值等),以準確判斷何時釋放。釋放原則:對象不再被引用。GC 採用有向圖模型:對象為頂點,引用為有向邊,線程為起始頂點。根可達對象為有效,不可達者可回收。此模型解決循環引用問題,精度高但效率較低;引用計數器效率高但難處理循環引用。
Java 內存洩漏:存在已分配對象,滿足(1)可達——有向圖中存在路徑可連接;(2)無用——程式後續不再使用。這類對象不被 GC 回收,卻佔用內存。C++ 中不可達對象也屬洩漏,範圍更大;Java 語言保證對象可達,不可達由 GC 管理,洩漏範圍較小。程式設計師只需管理引用(邊),無需管理對象釋放(頂點)。
GC 對開發者透明,System.gc() 僅是建議,不保證執行。JVM 採用多種觸發策略,GC 線程優先級低。特定場景(實時系統、遊戲)需調整參數,採用平滑回收(如增量式),避免突發停頓。Sun HotSpot JVM 支持此特性。
循環創建對象放入 Vector,僅置空局部引用,Vector 仍持有引用導致無法回收。解決:從集合移除對象或置空集合引用。
主流工具:Optimizeit Profiler、JProbe Profiler、JinSight、Rational Purify 等。原理:監測程式運行時對象申請、釋放等動作,統計分析可視化內存信息,幫助開發者定位無用但被引用的對象。以 Optimizeit 為例,支持 Application、Applet、Servlet、Remote Application,兼容多種 JVM 與操作系統。可監視內存使用曲線(堆大小、實際使用量),隨時暫停程式、強制 GC。提供四種視角:堆視角(所有對象統計)、方法視角(對象分配位置)、對象視角(入/出引用關係)、引用圖(從根頂點的出引用)。結合代碼熟悉度與調試經驗,可定位長期不釋放的無用對象,確認洩漏。
總結:Java 內存洩漏主因是對象不再使用但仍被引用。解決途徑:借助工具暴露堆中對象,尋找無用但被引用的對象並修正代碼。