You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

空闲状态下Tomcat堆内存呈锯齿状高占用的原因与排查方案

Tomcat 8.5.63空实例堆内存异常占用排查与优化

问题现象确认

即使webapps目录未部署任何业务应用,apache-tomcat-8.5.63仍存在如下内存表现:

  • 后台空闲运行状态下堆内存峰值达700MB,占用偏高
  • 无论是否挂载VisualVM,通过jstat -gc <vm id> 1000 1000命令观测到的内存表现无明显差异
  • 仅通过堆内存转储无法得到明确排查结论,单纯调整xmx、xms参数无法从根源解决长期内存占用问题

初始堆内存观测截图:
初始堆内存观测图

问题更新

Tomcat持续运行24小时后堆内存峰值出现明显下降,需确认该现象是否由后台监控工具导致,以及峰值下降的原因。
24小时后堆内存观测截图:
运行24小时堆内存观测图


排查与解决方案

先澄清一个常见认知误区:刚启动阶段的堆内存峰值高不代表存在内存泄漏,你观测到的24小时后峰值下降是Tomcat初始化完成、临时对象被GC回收的正常表现,和后台监控工具没有直接关系。

一、精准定位堆内对象类型的实操方法

不要上来就做全量堆dump,空实例高内存占用基本是默认冗余组件加载导致,按以下顺序排查效率更高:

  • 开启类加载日志定位冗余组件:修改bin/catalina.sh(Windows环境修改catalina.bat),在JAVA_OPTS配置项中追加参数-verbose:class,重启Tomcat后日志会打印所有加载的类及对应的来源jar包,空实例下如果出现非Tomcat内核自带的类,优先排查对应组件。
  • 用对象采样替代全量堆dump避免观测干扰:使用JDK8自带的JMC(Java Mission Control)连接Tomcat进程,开启对象分配采样功能,采样间隔设为10ms,连续观测10分钟即可统计出堆内常驻对象的类型、内存占比、分配调用栈,结果比全量堆dump更准确,也不会因为dump操作触发Full GC干扰正常内存表现。
  • 核对分代内存数据定位占用来源:执行jstat -gcutil <vm id> 1000 100重点关注两个指标:
    • 如果Old区长期占用低于200MB,Eden区呈现规律性波动,说明700MB峰值是年轻代默认分配空间过大导致,不存在常驻对象泄漏
    • 如果Old区占用持续上涨不回落,同步观测Metaspace占用:Tomcat 8.5默认会扫描所有jar包的注解信息,空实例下Metaspace加类关联对象占用100-200MB属于正常范围,超过300MB才属于异常

二、降低非必要内存占用的优化手段

调整xmx、xms只是硬限制堆内存上限,要从根源降低占用需要关闭默认配置中的冗余组件:

  • 彻底清理默认自带的web应用:很多人仅删除了ROOT目录,遗漏了docs、examples、host-manager、manager四个默认内置应用,这些应用启动时会加载大量Servlet、标签库类,空跑状态下就能占用200-300MB内存,全部删除后重启可先观测内存基线变化。
  • 关闭不需要的默认监听器与扫描规则:修改conf/server.xml,按需裁剪冗余组件:
    • 不需要JMX远程监控、生命周期事件推送的场景,仅保留JreMemoryLeakPreventionListener,注释掉其余所有默认Listener配置
    • 将所有Context节点的scanManifest、scanBootstrapClassPath属性设为false,关闭非必要的类路径扫描,空实例下这一项配置就能减少100-150MB的临时对象分配
    • 不需要WebSocket、JSP支持的场景,直接注释conf/web.xml中对应JSP Servlet、WebSocket相关的Servlet配置
  • 优化JVM分代内存比例:不要使用JVM默认的1:2新生代/老年代比例,空实例没有业务对象分配需求,给新生代分配128MB、老年代分配256MB完全足够,在JAVA_OPTS中追加参数-Xmn128m -XX:MaxMetaspaceSize=256m,重启后堆内存峰值基本不会超过400MB。

三、24小时后内存峰值下降的原因说明

该现象是Tomcat运行的正常表现,和监控工具无关:

  • Tomcat启动后的1-2小时内会执行JIT动态编译、类校验、注解扫描等初始化操作,这些操作会产生大量短期存活的临时对象,会将堆内存峰值推高
  • 所有初始化操作完成、JIT编译结束后,JVM触发Full GC会将这些临时对象全部回收,后续常驻对象规模基本不会出现大幅变动,堆内存峰值自然会回落到稳定基线,和你观测到的下降趋势完全吻合。

注意:如果Tomcat稳定运行3天后Old区占用仍在持续缓慢上涨,再排查是否触发Tomcat 8.5.63版本的已知内存泄漏bug,该版本存在WebSocket会话、JNDI资源引用的几个泄漏点,空实例下只要未开启WebSocket和JNDI资源就不会触发。


内容的提问来源于stack exchange,提问作者andreagalle

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 05:36:25