Tomcat 内存溢出(OutOfMemoryError)是生产环境常见故障。本文系统梳理 JVM 内存模型、常见 OOM 类型、排查工具链及调优实战,助你快速定位解决内存问题。
| 内存区域 | OOM 表现 | 典型原因 |
|---|---|---|
| 堆内存 | java.lang.OutOfMemoryError: Java heap space | 对象创建过快/内存泄漏/Xmx 设置过小 |
| 元空间 | java.lang.OutOfMemoryError: Metaspace | 类加载过多/动态代理/框架扫描包过大 |
| 直接内存 | java.lang.OutOfMemoryError: Direct buffer memory | NIO DirectByteBuffer 过多/未及时释放 |
| 线程栈 | java.lang.OutOfMemoryError: unable to create new native thread | 线程池配置过大/线程泄漏/栈大小设置过大 |
# 查看进程内存使用 jstat -gcutil1000 10 # 生成堆转储快照 jmap -dump:live,format=b,file=heap.hprof # 查看线程堆栈 jstack > thread_dump.txt
-Xlog:gc*:file=gc.log:time,uptime,level,tags,用 GCViewer 或 GCEasy 分析 GC 频率、耗时、内存回收效率现象:Full GC 频繁,老年代占用持续上升,最终 OOM
排查:MAT 分析发现 ArrayList 持有大量未释放的业务对象,代码中静态集合未清理
解决:
-Xms4g -Xmx4g -XX:NewRatio=2-XX:+UseG1GC -XX:MaxGCPauseMillis=200现象:重新部署应用后 Metaspace 持续增长
原因:类加载器未卸载,常见于使用 CGLIB、Spring AOP、JSP 动态编译场景
解决:
-XX:MaxMetaspaceSize=512m现象:堆内存正常,但物理内存持续上升,容器被 Kill
原因:Netty/Redis 客户端 DirectByteBuffer 未释放,或 -XX:MaxDirectMemorySize 未设置导致无限制增长
解决:
-XX:MaxDirectMemorySize=2gCleaner 或反射手动释放 DirectBufferTomcat OOM 本质是 JVM 内存管理问题。掌握「监控发现 → Dump 分析 → 代码定位 → 参数调优 → 验证复盘」的标准化排查流程,配合 MAT、Arthas 等利器,大多数内存问题可在小时级解决。预防胜于治疗,建立完善的监控体系与代码审查机制才是根本。