Java 通過可達性分析識別存活對象:從 GC Roots(棧局部變量、靜態字段、JNI 引用等)出發,能到達的對象為存活對象,不可達的為垃圾對象,回收其內存。
核心目標:防止內存耗盡、避免非法引用。
OutOfMemoryError。主 GC 具有不確定性,長期運行應用會反復觸發。
System.gc():只是建議,可能觸發 Full GC,增加停頓。null:幫助 GC 更快識別垃圾(局部變量無需,出作用域自動清除)。StringBuilder 代替 String 累加:避免產生大量中間字符串對象。int 比 Integer 省內存、無對象頭開銷。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
}
}
非傳統意義的「內存未釋放」,而是無意識持有對象引用,導致本可回收對象長期駐留堆中。
public Object pop() {
index--;
return stack[index]; // 數組仍持有引用!
}
// 正確:
public Object pop() {
Object obj = stack[--index];
stack[index] = null; // 斷開引用
return obj;
}
SoftReference、WeakHashMap、LinkedHashMap (LRU)。removeListener。OutOfMemoryError 或 GC 頻率/耗時異常。-Xlog:gc*),確認老年代佔用持續上升。jmap -histo、jhat、Arthas、MAT (Eclipse Memory Analyzer)、JProfiler、Async Profiler。理解可達性分析、分代假設、GC 觸發條件是調優基石。良好編碼習慣(少臨時對象、斷開引用、用基本類型、緩存加上限)能解決 90% 問題。複雜洩漏需工具輔助分析,MAT + Arthas 是現代最佳組合。