Tomcat内存溢出排查:从日志定位到JVM参数调整
Tomcat内存溢出排查的核心思路是:先通过日志确认溢出类型和触发位置,再用JDK自带工具观察堆内存变化,最后结合业务代码或JVM参数调整解决。
本文适用于使用Tomcat部署Java Web应用、遇到OutOfMemoryError或服务频繁无响应的场景。
先确认溢出类型和日志位置
Tomcat本身不会单独记录内存溢出,错误通常出现在应用日志或catalina.out中。
先找到日志目录,常见路径为/usr/local/tomcat/logs/或宝塔面板中站点对应的Tomcat日志目录。
执行以下命令搜索关键字:
grep -i "OutOfMemoryError" catalina.out
常见类型有三种:
Java heap space:堆内存不足,最典型,通常和对象过多或泄漏有关。Metaspace:元空间不足,常见于频繁热部署或动态生成类。GC overhead limit exceeded:GC占用过高但回收效果差,本质仍是堆内存问题。
记下报错前几行的业务类名或Servlet路径,这能帮你判断是哪个功能触发。
用JDK工具观察内存和线程
确认溢出后,不要急着重启。
先用jps找到Tomcat进程号:
jps -l
输出中带有Bootstrap的通常是Tomcat主进程。
假设PID为12345,执行:
jstat -gcutil 12345 1000 10
重点关注O列(老年代使用率)和FGC列(Full GC次数)。
如果O接近100%且FGC持续增长,说明老年代无法回收。
接着生成堆快照,便于后续分析:
jmap -dump:format=b,file=/tmp/tomcat_heap.hprof 12345
如果服务器内存紧张,可先只统计对象:
jmap -histo:live 12345 | head -30
查看实例数最多的类,通常能发现异常集合或缓存对象。
调整JVM参数并验证
如果确认是堆内存不足而非代码泄漏,可以调整Tomcat启动参数。
编辑bin/catalina.sh,在文件开头添加:
export JAVA_OPTS="-Xms512m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=256m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/"
参数说明:
-Xms和-Xmx分别设置初始和最大堆,建议设为相同值避免动态调整。-XX:MaxMetaspaceSize限制元空间,防止无限增长。-XX:+HeapDumpOnOutOfMemoryError让JVM在溢出时自动导出快照。
修改后重启Tomcat,用jstat再次观察。
如果老年代使用率稳定、Full GC频率下降,说明参数调整有效。
若溢出仍反复出现,需要回到代码层面检查是否有静态集合持续增长或未关闭的资源。
避坑与常见疑问
不要直接kill -9进程。
强制杀进程可能丢失堆快照,建议先执行jmap再重启。
堆内存不是越大越好。-Xmx超过物理内存会导致系统交换,反而拖慢响应。
一般留出1GB左右给操作系统和其他进程。
Metaspace溢出不一定靠加参数解决。
如果应用频繁热部署或使用大量动态代理,需要检查框架配置。
问:调整参数后需要观察多久?
答:建议至少观察一个完整业务高峰周期,确认Full GC次数和响应时间恢复正常。
问:没有JDK工具怎么办?
答:确认服务器安装的是JDK而非JRE,jps、jstat、jmap都在JDK的bin目录下。
问:堆快照文件太大无法分析?
答:可在本地用MAT或VisualVM打开,重点看支配树和泄漏嫌疑报告。
排查完成后,建议把JAVA_OPTS配置和日志路径记录到运维文档中,方便下次快速定位。
如果应用本身存在内存泄漏,仅靠调参只能延缓问题,仍需结合代码审查和压测验证。