java.lang.OutOfMemoryError (OOM) 是 Java 開發中最令開發者頭疼的錯誤之一。它不僅意味著應用崩潰,更往往暴露出代碼設計缺陷、配置不當或架構問題。本文系統梳理 OOM 根因分類、常見錯誤提示、代碼層面排查策略、實戰案例,並針對 Tomcat、WebLogic、JBoss、Resin、Eclipse 等主流容器提供針對性配置調優方案。
| 類別 | 典型表現 | 根本原因 |
|---|---|---|
| 堆內存不足 | Java heap space | 對象過多/過大、內存洩漏、堆設置過小 |
| 元空間/永久代不足 | PermGen space / Metaspace | 類加載過多、類卸載失敗、常量池溢出 |
| 直接內存不足 | Direct buffer memory | NIO 直接緩衝區過大、未及時釋放 |
| 線程棧溢出 | Unable to create new native thread | 線程數過多、棧大小設置過大 |
| GC 開銷過大 | GC overhead limit exceeded | 可用內存極低但 GC 回收極少,陷入長時間 GC |
場景 現象 根因 解決方案 Hibernate 大量查詢 OOM 一次加載十萬條記錄 分頁查詢、流式處理、 setFetchSize壓力測試 OOM Session 未釋放 調用 session.invalidate()、縮短超時時間業務邏輯 OOM 死循環生成對象 修正循環條件、添加熔斷機制 Tomcat 部署 OOM 堆/永久代配置過小 調大 JVM 參數 五、主流容器 JVM 參數調優方案
1. Tomcat:Java heap space
原理:JVM 默認
-Xms(初始堆) = 物理內存 1/64,-Xmx(最大堆) = 物理內存 1/4。建議-Xms = -Xmx避免震盪,-Xmn(新生代) ≈ 1/4-Xmx。修改:
TOMCAT_HOME/bin/catalina.sh(Linux) 或catalina.bat(Windows),在echo "Using CATALINA_BASE..."前添加:JAVA_OPTS="-server -Xms800m -Xmx800m -XX:MaxNewSize=256m"建議:堆最大不超過物理內存 80%,預留給 OS、Metaspace、Code Cache、Thread Stacks、Direct Memory。
2. Tomcat:PermGen space (JDK 7) / Metaspace (JDK 8+)
原理:永久代存放 Class/Method 元數據,默認僅 4-64MB。大量 JSP 編譯、第三方 Jar、動態代理類會撐爆。
修改:同目錄下添加:
# JDK 7 永久代 JAVA_OPTS="-server -XX:PermSize=64M -XX:MaxPermSize=128M" # JDK 8+ 元空間 JAVA_OPTS="-server -XX:MetaspaceSize=128M -XX:MaxMetaspaceSize=256M"優化:將公共第三方 Jar 移至
tomcat/shared/lib,減少重複加載佔用。3. WebLogic
修改:
bea/weblogic/common/bin/commEnv.sh:if [ "${PRODUCTION_MODE}" = "true" ]; then JAVA_VM="-server" MEM_ARGS="-Xms256m -Xmx512m -XX:MaxPermSize=256m" else JAVA_VM="-client" MEM_ARGS="-Xms256m -Xmx512m -XX:MaxPermSize=256m" fi JAVA_OPTIONS="${JAVA_OPTIONS} -Xverify:none"4. Eclipse 運行 JBoss:PermGen space
- Debug 圖標旁小箭頭 → Debug Configurations
- 左側 Generic Server → JBoss v4.2 at localhost
- Arguments 標籤 → VM arguments 添加:
-Dprogram.name=run.bat -Djava.endorsed.dirs="D:/JBoss405/bin/../lib/endorsed" -Xms128m -Xmx512m -XX:PermSize=64m -XX:MaxPermSize=256m命令行模式修改
bin/run.conf中JAVA_OPTS追加-XX:PermSize=64m -XX:MaxPermSize=256m。5. Resin
修改:
/usr/local/resin/bin/httpd.sh中args參數:args="-Xms128m -Xmx256m"根據服務器實際配置由運維設置。
六、進階排查工具鏈
| 工具 | 用途 | 核心命令/操作 |
|---|---|---|
| jstat | 實時 GC/堆統計 | jstat -gcutil pid 1000 |
| jmap | 堆轉儲 | jmap -dump:live,format=b,file=heap.hprof pid |
| jhat / MAT | 堆分析 | MAT: Histogram → Dominator Tree → Path to GC Roots |
| VisualVM / JConsole | 圖形化監控 | 監控堆、線程、類加載、MBean |
| Arthas | 線上診斷 | dashboard, heapdump, oom |
listAll() 類接口clear()、賦 null,縮短引用鏈OOM 不是不可戰勝的敵人,而是系統發出的求救信號。通過代碼規範預防、容器參數調優緩解、工具鏈精準定位三位一體,構建穩健的 Java 應用內存防線。記住:內存洩漏最終都會演變成 OOM,盡早釋放無用引用是根本之道。