記憶體分配與回收耗時往往超過實際資料運算。C++ 手動控制雖靈活但風險高,Java 採用垃圾收集(GC)自動管理。但 GC 引發的「停頓」曾是即時系統拒用 Java 的核心理由。大型應用 GC 停頓可達數秒,足以中斷即時通訊或控制系統。Java 5.0 引入人因工程,目標是最少命令列調優即獲得最佳效能。
+------------------ Heap ------------------+ | Young Generation | | +--------+ +----------+ +----------+ | | | Eden | | Survivor | | Survivor | | | | Space | | From | | To | | | +--------+ +----------+ +----------+ | +------------------------------------------+ | Old Generation | | (Tenured / Long-lived objects) | +------------------------------------------+ | Permanent Generation | | (Class/Method metadata, interned Strings)| +------------------------------------------+
MaxTenuringThreshold,預設 15) → 晉升 Old GenerationString.intern() 字串Java 5.0 根據應用特徵自動選擇:
| 指標 | 定義 | 關注場景 |
|---|---|---|
| 吞吐量 | 非 GC 時間佔總時間比例 | 批次處理、科學計算、離線任務 |
| 停頓時間 | 應用因 GC 凍結的時間 | 即時系統、Web 服務、遊戲伺服器 |
| 佔用率 | 工作集頁數/緩衝行數 | 記憶體受限環境、高密度部署 |
| 響應性 | 物件死亡到記憶體可用的延遲 | 分散式系統、RMI、弱引用清理 |
代大小選擇直接影響以上指標權衡:Young 代大 → Minor GC 頻率低但單次久,Old 代大 → Full GC 頻率低但單次極久。
| 組合 | Young 代 | Old 代 | 特點 |
|---|---|---|---|
| Serial | 單執行緒複製 | 單執行緒標記-整理 | Client 模式預設,單核、小堆 |
| Parallel Scavenge | 多執行緒複製 | 單執行緒標記-整理 | 吞吐量優先,可設目標吞吐量 |
| Parallel Old | 多執行緒複製 | 多執行緒標記-整理 | 全並行,大堆、多核、吞吐量導向 |
| CMS | 單/多執行緒複製 | 並行標記-清除 | 低停頓優先,碎片整理需 Full GC |
# 吞吐量優先(批次/計算)
-server -XX:+UseParallelGC -XX:+UseParallelOldGC -Xms2g -Xmx2g
# 低停頓優先(Web/即時)
-server -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -Xms2g -Xmx2g -XX:CMSInitiatingOccupancyFraction=70
-XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCApplicationStoppedTime -Xloggc:gc.log
NewRatio、SurvivorRatioCMSInitiatingOccupancyFraction、MaxTenuringThresholdWeakHashMap、SoftReference 避免強引用阻礙回收intern() 謹慎使用Java 5.0 GC 以分代收集為核心,人因工程降低調優門檻。理解分代假說、收集器特性、效能指標權衡,結合 GC 日誌分析與編碼優化,能構建高吞吐、低停頓的 Java 應用。現代 JDK(8/11/17/21)引入 G1、ZGC、Shenandoah 等低延遲收集器,進一步推向毫秒級甚至亞毫秒級停頓目標,但核心原理與調優思維始終相通。