Java 記憶體分為三大區域:
new 出來的物件實例、陣列,GC 主戰場GC 採用 可達性分析:從 GC Roots(執行緒棧局部變數、靜態屬性、常量、JNI 參考)出發,不可達物件視為垃圾回收。記憶體洩漏本質:物件仍可達但程式不再使用,導致 GC 無法回收,長期佔用堆空間。
static Vector v = new Vector();
for (int i=0; i<100; i++) {
Object o = new Object();
v.add(o);
o = null; // 僅切斷局部參考,Vector 仍持有
}
對策:用完後 v.clear() 或 v = null;避免長生命週期集合累積短生命物件。
HashSet 依賴 hashCode()/equals();修改參與雜湊計算的欄位後,remove() 找不到原位置,導致物件殘留。
對策:不可變物件作 Key/Element;或先 remove 再修改再 add。
addXXXListener() 後未對應 removeXXXListener(),被觀察者持有觀察者參考,阻礙回收。
Connection、Statement、ResultSet 必須在 finally 顯式 close()InputStream/OutputStream/Socket 同理OuterClass.this 參考對策:static 內部類 + WeakReference<Outer>;onDestroy() 移除訊息 handler.removeCallbacksAndMessages(null)。
單例生命週期 = 應用進程;若持有短生命物件參考 → 洩漏。Android 中傳入 Application Context 而非 Activity Context。
recycle() 再 null(釋放 Native 記憶體)ViewHolder 復用 convertViewlazy init + 適時清空BroadcastReceiver、ContentObserver、Cursor、File、Stream 必須在對應生命週期註銷/關閉| 類型 | 回收時機 | 適用場景 |
|---|---|---|
| Strong | 永不主動回收 | 核心業務物件 |
| SoftReference | 記憶體不足前 | 圖片快取、大物件緩衝 |
| WeakReference | 下次 GC 時 | 監聽器、快取、非關鍵引用 |
| PhantomReference | 最終化前 | 精確追蹤回收、DirectBuffer 清理 |
「誰創建、誰釋放」,保持對物件生命週期敏感,是根治記憶體洩漏的核心心法。