「GC 只回收它認為的垃圾,不是你認為的垃圾。」理解 JVM 內存模型與 GC 行為,是編寫高性能、低延遲 Java 代碼的前提。本文從對象生命週期、分配優化、GC 調優三個維度,提供可落地的實戰策略。
關鍵認知:不可達 ≠ 立即回收。GC 以「停頓換吞吐」或「低延遲換吞吐」為代價批量處理,中間存在時間窗口。
// 反例:循環中創建臨時對象
for (int i = 0; i < 10000; i++) {
Object obj = new Object(); // 10000 個臨時對象堆積待 GC
}
// 正例:循環外復用 / 基本類型 / 值傳遞
Object obj = null;
for (int i = 0; i < 10000; i++) {
obj = new Object(); // 僅 1 個引用變量,對象若無逃逸可標量替換/棧上分配
}
// 避免重複初始化
public class A {
private Map map = new HashMap<>(); // 字段初始化
public A() {
// map = new HashMap<>(); // 錯誤:構造器再次初始化,首個實例成垃圾
}
}
Cleaner (Java 9+)、PhantomReference + `ReferenceQueue` 實現資源確定性釋放。
// 反例:默認容量 10,擴容拷貝產生大量中間數組
List list = new ArrayList<>();
for (int i = 0; i < 100000; i++) list.add(i);
// 正例:預估容量,一次性分配
List list = new ArrayList<>(100000);
int[] array = new int[100000]; // 確定大小優先用基本類型數組
// 圖片、大數據結構緩存,內存不足時自動釋放
SoftReference ref = new SoftReference<>(loadBitmap());
Bitmap bitmap = ref.get();
if (bitmap == null) { bitmap = loadBitmap(); ref = new SoftReference<>(bitmap); }
靜態字段生命週期 = 類加載器生命週期,易造成「類級別內存洩漏」。僅當:對象大、壽命長、數據穩定、多實例共享需求時使用,否則優先考慮緩存框架 (Caffeine、EhCache) 管理生命週期。
// 通用對象池骨架 (生產環境直接用 Apache Commons Pool / HikariCP)
public abstract class ObjectPool {
private final BlockingQueue available = new LinkedBlockingQueue<>();
private final AtomicInteger created = new AtomicInteger();
protected abstract T create();
protected abstract void reset(T obj); // 重置狀態
protected abstract boolean validate(T obj);
public T borrow() {
T obj = available.poll();
if (obj == null || !validate(obj)) obj = create();
return obj;
}
public void release(T obj) {
reset(obj);
available.offer(obj);
}
}
// 線程池、連接池、解析器池、大對象緩衝池均適用
警惕:池化引入同步開銷、狀態重置複雜度、死鎖風險,需壓測驗證收益 > 成本。
| 參數 | 含義 | 典型設定 | 適用場景 |
|---|---|---|---|
| -Xms / -Xmx | 堆初始/最大值 | 設為相等 (如 4g),避免動態擴縮容抖動 | 生產環境必設 |
| -Xmn / -XX:NewRatio | 新生代大小 / 老年代比例 | -Xmn 1.5g 或 -XX:NewRatio=2 | 高分配率應用調大新生代 |
| -XX:SurvivorRatio | Eden:Survivor 比例 | 8 (默認) → 6-10 視對象存活率調整 | 減少過早晉升老年代 |
| -XX:MaxTenuringThreshold | 晉升老年代年齡閾值 | 15 (默認) / 0 (直接進老年代) | 大對象直接入老年代設 0-1 |
| -XX:+UseG1GC | 啟用 G1 收集器 | Java 9+ 默認,大堆 (>4G) 低延遲首選 | 替代 CMS/Parallel |
| -XX:MaxGCPauseMillis | G1 目標停頓時間 | 200ms (默認) → 50-100ms 低延遲場景 | 權衡吞吐與延遲 |
| -XX:+UseZGC / -XX:+UseShenandoahGC | 超低延遲收集器 | JDK 11+/12+,堆 100G+ 亞毫秒級停頓 | 極致低延遲、大內存機器 |
| -XX:+HeapDumpOnOutOfMemoryError | OOM 時導出堆快照 | -XX:HeapDumpPath=/logs/heap.hprof | 生產環境必開,事後分析 |