首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

解決 java.lang.OutOfMemoryError: allocLargeArray 記憶體溢位完整指南

     編輯:Java 相關知識

錯誤現象與核心原因

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 耗盡。

即時緩解方案

A. 調整 JVM Heap 參數

在 catalina.sh / catalina.bat 或啟動腳本中設定:

JAVA_OPTS="-Xms2g -Xmx4g -Xmn1536m"
  • -Xms:初始 Heap 大小,建議與 -Xmx 相同,避免動態擴縮帶來的 GC 抖動
  • -Xmx:最大 Heap,不超過實體記憶體 70-80%
  • -Xmn:Young Generation 大小,建議約為 -Xmx 的 1/3~1/2

B. 開啟 GC 日誌進行深度分析

JAVA_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,找出大物件佔用者。

JVM 記憶體模型與 GC 原理深度解析

Heap 三大區域

  • Young Generation (Eden + S0 + S1):新物件誕生地,Minor GC 高頻、速度快
  • Old Generation:經過多次 Minor GC 仍存活的物件晉升至此,Major/Full GC 觸發於此
  • Metaspace (JDK 8+):類元數據、常數池,取代 PermGen,預設無上限需設定 -XX:MaxMetaspaceSize

四大 GC 演算法對比

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。

常見導致頻繁 GC 的程式碼模式

  • 手動呼叫 System.gc() —— 嚴禁,交給 JVM 決定
  • 大量短命物件分配(如循環中 new String()、StringBuilder 未複用)
  • 集合未預估容量:new ArrayList() → 擴容複製開銷大,改用 new ArrayList<>(預估大小)
  • 記憶體洩漏:靜態集合持有參考、ThreadLocal 未清理、連線/流未關閉

Stack 設定與執行緒數關係

-Xss512k  # 每執行緒堆疊 512KB,預設 1MB

MaxThreads ≈ (實體記憶體 - Heap - Metaspace - OS保留) / Xss。過大 -Xss 限制執行緒數,過小導致 StackOverflowError。

硬體層面優化清單

  1. 使用 SSD 提升 GC 期間磁碟 I/O(Heap Dump、Swap)
  2. 關閉 Swap 或設定 vm.swappiness=1,避免 JVM 頁面被換出導致 GC 停頓飆升
  3. NUMA 架構綁定 CPU:-XX:+UseNUMA
  4. 大頁面記憶體:-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"

排查檢查清單

  1. 確認 -Xmx 是否過小?
  2. GC 日誌是否顯示 Full GC 後 Heap 釋放 < 30%?
  3. 是否有大量 allocLargeArray / humongous allocation (G1)?
  4. 業務是否存在大批次導入、報表產生等瞬時大物件分配?
  5. Thread Dump 是否有大量 BLOCKED/WAITING 執行緒?

結語

allocLargeArray 本質是 Heap 空間不足。解決路徑:調大 Heap → 選對 GC → 開啟 GC Log → 分析物件分佈 → 修碼優化 → 壓測驗證。切勿單純加記憶體而忽略程式碼層面的大物件分配模式。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved