Tomcat 日誌出現:
Caused by: java.lang.OutOfMemoryError: allocLargeArray - Object size: 80040, Num elements: 40010
解讀: JVM 嘗試在 Heap 分配一個 80,040 位元組(約 78 KB)的陣列,包含 40,010 個元素,但 Heap 可用空間不足。此錯誤屬於 Heap 空間耗盡,而非 Metaspace 或 Stack 耗盡。
在 catalina.sh / catalina.bat 或啟動腳本中設定:
JAVA_OPTS="-Xms2g -Xmx4g -Xmn1536m"
-Xms:初始 Heap 大小,建議與 -Xmx 相同,避免動態擴縮帶來的 GC 抖動-Xmx:最大 Heap,不超過實體記憶體 70-80%-Xmn:Young Generation 大小,建議約為 -Xmx 的 1/3~1/2JAVA_OPTS="$JAVA_OPTS -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/var/log/tomcat/gc-%t.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=100M"
配合 jstat -gcutil <pid> 1000、jmap -histo:live <pid>、Eclipse MAT 分析 Heap Dump,找出大物件佔用者。
-XX:MaxMetaspaceSize| GC 類型 | 啟動參數 | 適用場景 | 特點 |
|---|---|---|---|
| Serial GC | -XX:+UseSerialGC | 單核、小記憶體、Client 模式 | 單執行緒、Stop-the-world 時間長 |
| Parallel GC (Throughput) | -XX:+UseParallelGC | 多核、批次處理、高吞吐優先 | Young 區多執行緒,Old 區單執行緒 |
| CMS (Concurrent Mark Sweep) | -XX:+UseConcMarkSweepGC | 低延遲、Web 服務、互動式應用 | Old 區並發標記清除,有碎片整理問題 |
| G1 (Garbage First) | -XX:+UseG1GC | 大記憶體 (6GB+)、混合負載、JDK 9+ 預設 | 分區整理、可預測停頓、Region 架構 |
生產環境建議: JDK 8 用 -XX:+UseConcMarkSweepGC 或 -XX:+UseG1GC;JDK 11+ 直接用預設 G1。
System.gc() —— 嚴禁,交給 JVM 決定new String()、StringBuilder 未複用)new ArrayList() → 擴容複製開銷大,改用 new ArrayList<>(預估大小)-Xss512k # 每執行緒堆疊 512KB,預設 1MB
MaxThreads ≈ (實體記憶體 - Heap - Metaspace - OS保留) / Xss。過大 -Xss 限制執行緒數,過小導致 StackOverflowError。
vm.swappiness=1,避免 JVM 頁面被換出導致 GC 停頓飆升-XX:+UseNUMA-XX:+UseLargePages(需 OS 支援)JAVA_OPTS="
-server
-Xms4g -Xmx4g -Xmn1536m
-XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m
-XX:+UseG1GC -XX:MaxGCPauseMillis=200
-XX:+PrintGCDetails -XX:+PrintGCDateStamps
-Xloggc:/data/logs/gc.log
-XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=100M
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/dumps/
-XX:+UseLargePages -XX:+UseNUMA
-Xss512k
-Dfile.encoding=UTF-8 -Duser.timezone=Asia/Taipei"
-Xmx 是否過小?allocLargeArray / humongous allocation (G1)?allocLargeArray 本質是 Heap 空間不足。解決路徑:調大 Heap → 選對 GC → 開啟 GC Log → 分析物件分佈 → 修碼優化 → 壓測驗證。切勿單純加記憶體而忽略程式碼層面的大物件分配模式。