Tomcat日志中出现内存溢出如何解决
小樊
44
2025-12-25 11:57:28
Tomcat 内存溢出定位与解决
一、先判定 OOM 类型
- 查看 catalina.out 或 localhost..log 中的异常关键字,常见有:
- Java heap space:堆内存不足,对象分配失败。
- PermGen space:永久代不足(主要发生在 Java 7 及更早)。
- Metaspace:元空间不足(Java 8+)。
- unable to create new native thread:无法创建新线程,多与系统/容器线程数限制相关。
- 结合日志时间点与业务高峰,判断是突发流量、部署后持续恶化,还是运行很久后逐步变差,从而决定是“扩容参数”还是“查泄漏/控并发”。
二、快速缓解与参数调整
- 调整堆大小(适用于 heap space)
- 原则:将 -Xms 与 -Xmx 设为相同,避免运行期扩缩堆带来的抖动;一般将最大堆控制在物理内存的约 1/4,且不超过约 80%,为系统与其他进程留余量。
- 示例(Linux,编辑 bin/catalina.sh,在合适位置追加到 JAVA_OPTS):
- JAVA_OPTS=“$JAVA_OPTS -Xms2g -Xmx2g”
- 调整元空间(适用于 Java 8+ 的 Metaspace)
- 示例:
- JAVA_OPTS=“$JAVA_OPTS -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m”
- 调整永久代(适用于 Java 7 及更早的 PermGen)
- 示例:
- JAVA_OPTS=“$JAVA_OPTS -XX:PermSize=128m -XX:MaxPermSize=256m”
- 选择合适的 GC(示例)
- JAVA_OPTS=“$JAVA_OPTS -XX:+UseG1GC”
- 修改后重启 Tomcat 并验证进程参数是否生效(如:ps -ef | grep tomcat)。上述做法可快速缓解因默认内存过小或元空间/永久代不足导致的问题。
三、按场景给出配置示例
- Linux 解压版 Tomcat(catalina.sh)
- 建议位置:在 “cygwin=false” 这一行之前添加(或追加到既有 JAVA_OPTS):
- JAVA_OPTS=“$JAVA_OPTS -Xms2g -Xmx2g -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m -XX:+UseG1GC”
- Windows 解压版(catalina.bat)
- 在文件靠前位置(如 @echo off 之后)添加:
- set JAVA_OPTS=-Xms2g -Xmx2g -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m -XX:+UseG1GC
- Windows 安装版(服务方式,tomcat8w.exe)
- 运行 tomcat8w.exe → Java 选项卡 → 设置 Initial memory pool 与 Maximum memory pool(如 2048、4096),保存并重启服务。
- 验证
- 重启后用命令查看进程参数与内存:ps -ef | grep tomcat;或在 /manager/status(需配置用户)查看 JVM Free/Total/Max memory。
四、定位根因与长期治理
- 监控与 GC 分析
- 实时观察:使用 jstat -gcutil 1000 查看 YGC/YGCT、FGC/FGCT、GCT 等指标,判断是否频繁 Full GC 或 GC 时间过长。
- 堆转储与泄漏分析:在问题发生时抓取堆快照(如 jmap -dump:live,format=b,file=heap.hprof ),用 MAT/VisualVM 分析大对象与支配树,定位泄漏来源(缓存、会话、静态集合、ThreadLocal、未关闭资源等)。
- 应用与容器配置优化
- 线程与连接:在 server.xml 的 中合理设置 maxThreads、minSpareThreads、acceptCount,避免并发过高导致线程与内存压力叠加;必要时降低峰值并发、启用队列与限流。
- 缓存与对象生命周期:控制本地缓存大小与过期策略,及时释放大对象、关闭 ResultSet/Statement/Connection,避免长生命周期引用。
- 代码与依赖:排查重复加载类、热部署频繁导致的元空间压力,减少不必要的依赖与类生成。
- 运维与预防
- 建立基线监控(如 Prometheus + Grafana),对 Heap/Meta/线程数/GC 设置告警;定期回归压测与内存分析,必要时升级 JDK/Tomcat 稳定版本。
五、常见误区与建议
- 只加内存不治本:堆/元空间扩容能“顶住”一阵,但若存在泄漏或设计问题,最终仍会 OOM;应结合 堆转储 + 分析 根治。
- 过度分配堆:将 -Xmx 设得过大(如接近或超过物理内存的 80%)会引发系统 swap、GC 停顿过长与稳定性风险;应结合负载与 GC 表现逐步调优。
- 忽视线程与连接:高并发带来线程栈与对象压力,需与 maxThreads/acceptCount 及后端连接池联动治理,而非单靠堆扩容。