生產環境 Tomcat 記憶體設定不當極易發生 OOM。三大常見情境:
OutOfMemoryError: Java heap spaceOutOfMemoryError: PermGen spaceOutOfMemoryError: unable to create new native thread-Xms 初始堆大小、-Xmx 最大堆大小-XX:PermSize 永久區初始大小、-XX:MaxPermSize 永久區最大值建議 -Xms -Xmx 設相同值(如 set JAVA_OPTS= -Xms1024m -Xmx1024m)。堆大小受限於:OS 資料模型(32 位約 1.5-2GB)、可用虛擬/實體記憶體。可用 java -Xmx***M -version 測試上限。
JVM 98% 時間用於 GC 且可用 Heap < 2% 時拋出。無洩漏下調整 -Xms -Xmx 解決。
PermGen space 存放 Class/Meta 資訊,Class 載入時置入,GC 主程序運行期不清理。大量載入 Class(如 JSP 預編譯、Hibernate/Spring 動態類)易溢出。加大 -XX:PermSize -XX:MaxPermSize 解決,常與堆設定結合:set JAVA_OPTS= -Xms1024m -Xmx1024m -XX:PermSize=128M -XX:MaxPermSize=256M。注意:java -Xmx***M -version 測試上限為 -Xmx + -XX:MaxPermSize 之和。
較少見,與 JVM/系統記憶體比例相關。現象:分配 JVM 記憶體越多(如 1.5GB),執行緒多時越易發生。
根因:32 位進程最大 2GB 可用記憶體(另 2GB 核心保留)。假設 JVM 1.5GB,剩 500MB 扣除系統 DLL 載入約剩 400MB。建立執行緒時:JVM 內建 Thread 物件,OS 同時在剩餘 400MB 建立實體執行緒(非 JVM 堆)。JDK 1.4 預設堆疊 256KB,JDK 1.5 預設 1MB/執行緒 → 400MB 僅能建 ~400 執行緒。
結論:欲建更多執行緒,必須減少 JVM 最大記憶體。或讓 JVM 寄宿於 JNI 代碼中。
估算公式:(MaxProcessMemory - JVMMemory - ReservedOSMemory) / ThreadStackSize = Number of threads
JDK 1.5 假設 OS 保留 120MB:
1.5GB JVM: (2GB-1.5GB-120MB)/1MB ≈ 380 threads
1.0GB JVM: (2GB-1.0GB-120MB)/1MB ≈ 880 threads
Windows boot.ini 啟動選項 /PAE /3G 可擴充用戶進程至 3GB(核心僅佔 1GB),可建更多執行緒。需結合 OS 層面調整。
須針對不同情境診斷記憶體分配,從根本解決問題。