tomcat内存溢出本质是jvm配置与负载不匹配,需先通过日志定位类型(如java heap space、metaspace或unable to create new native thread),再用jstat/jvisualvm监控确认瓶颈,最后针对性调参(如-xms/-xmx统一设为2g、-xmn512m、-xx:maxmetaspacesize=512m),并结合代码优化(去重jar、关闭资源、避免大缓存)和压测验证。

Tomcat 部署中遇到内存溢出(OutOfMemoryError),本质是 JVM 内存配置与应用实际负载不匹配。排查要从日志定位类型、监控确认瓶颈、再针对性调参,不是盲目加内存。
看日志确认溢出类型
打开 catalina.out 或应用日志,重点识别错误前缀:
- java.lang.OutOfMemoryError: Java heap space → 堆内存不足,对象分配失败,最常见
- java.lang.OutOfMemoryError: Metaspace(Java 8+)或 PermGen space(Java 7 及以前)→ 类元数据过多,如大量动态生成类、JSP 预编译、冗余 jar 包
- java.lang.OutOfMemoryError: unable to create new native thread → 线程数超限,常因连接池/线程池配置过大或系统级限制
注意:Java 8 起已用 Metaspace 替代 PermGen,参数变为 -XX:MetaspaceSize 和 -XX:MaxMetaspaceSize。
查运行时堆使用情况
不要只靠猜,用工具验证:
Apache Superset 是一个广泛采用的开源 BI 平台,用于 SQL 探索、图表构建和仪表板交付。当代理需要查询仓库数据、组装仪表板或使用成熟的分析界面解释指标而不是临时笔记本代码时,此技能非常有用。
- 启动时加 JVM 参数开启 GC 日志:
-Xloggc:gc.log -XX:+PrintGCDetails -XX:+PrintGCTimeStamps,观察是否频繁 Full GC 且回收后空间仍极小 - 用
jstat -gc <pid></pid>实时查看 Eden、Survivor、Old、Metaspace 使用率 - 用
jvisualvm或jconsole连接 Tomcat 进程,直观看堆内存曲线和对象分布 - 若发现老年代持续增长且不下降,可能存在内存泄漏,需用
jmap -histo <pid></pid>或 dump 后用 MAT 分析大对象
安全调整堆大小参数
修改 JVM 启动参数,核心是控制堆(heap)和元空间(metaspace):
- 统一初始与最大堆大小:
-Xms2g -Xmx2g(例如设为 2GB),避免运行中反复扩容缩容 - 年轻代建议占堆的 1/4 左右:
-Xmn512m(对应上例),有助于减少 Minor GC 频率 - 元空间按需设置上限(Java 8+):
-XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m,防无限膨胀 - 栈空间一般保持默认(
-Xss1m),除非明确有深度递归或大量线程
参数写入位置取决于启动方式:
- Linux:在
$CATALINA_HOME/bin/setenv.sh中添加(无则新建),内容如:
JAVA_OPTS="-server -Xms2g -Xmx2g -Xmn512m -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m" - Windows:在
%CATALINA_HOME%\bin\setenv.bat中添加类似语句 - 服务方式(如 Windows 服务或 systemd):需通过对应管理界面或 service 文件修改 JVM 选项,不能改 catalina.sh/bat
配合代码与部署优化
光调参数治标不治本,还需检查应用本身:
- 避免在 Servlet 或 Filter 中缓存大量数据(如全量数据库查询结果)
- JSP 尽量少用 scriptlet,预编译可关掉(
web.xml中设jsp-config的development为 false) - 第三方 jar 包去重:把共用 jar 移到
$CATALINA_HOME/lib,而非每个应用的WEB-INF/lib - 数据库连接、流、IO 资源务必显式关闭,防止因未释放导致对象长期驻留老年代
调参后务必压测验证,观察 GC 行为和响应稳定性,而不是只看“不报错”。










