Tomcat 内存只涨不跌:堆外与引用两本账

直接答案:Java 应用内存上涨不回落,多数不是"溢出",而是两本账没分开——堆内老年代对象迟迟不被回收(仍被引用,GC 拿它没办法),以及堆外内存(元空间、直接内存、线程栈)根本不归堆参数管。先定性再动手,别一上来就调大内存。

取证的顺序

jstat -gcutil 1000 连续观察:老年代使用率在多次 Full GC 后居高不下,说明对象仍被引用——翻代码找静态集合、缓存无上限、监听器未注销这类持有链。jmap -histo 看实例排行,哪类对象数量异常一眼便知;要细看引用链用 jmap -dump 配 MAT 分析支配树。如果堆内平稳而进程 RSS 还在涨,账在堆外:元空间类加载器泄漏(频繁热部署的典型伤)、NIO 直接内存、线程数增长,分别查部署次数、直接内存配置与线程池创建。

配置的正确姿势

启动参数 -Xms 与 -Xmx 设一致,避免堆伸缩抖动;-XX:+HeapDumpOnOutOfMemoryError 留证据,真溢出时现场自动保存。但记住纪律:调大内存只是买时间,引用链不解,涨势迟早顶到新上限。

升级与重启的两句补充

运行环境大版本升级前在测试环境把内存曲线跑一轮:新版本的元空间行为与默认参数有差异,带着旧参数直接上生产,等于换了一台车的发动机还用旧地图开车。例行重启窗口要固定并留记录——“重启能缓解"本身就是一条诊断信息,缓解周期越来越短,说明泄漏在加速。

升级与重启的两句补充

运行环境大版本升级前在测试环境把内存曲线跑一轮:新版本的元空间行为与默认参数有差异,带着旧参数直接上生产,等于换了一台车的发动机还用旧地图开车。例行重启窗口要固定并留记录——“重启能缓解"本身就是一条诊断信息,缓解周期越来越短,说明泄漏在加速。

预防三条

缓存必须带上限与过期;热部署频繁的环境定期重启窗口化;监控里给老年代使用率与 Full GC 频率设阈值告警,别等用户报卡顿才知道。贵州诚鑫致达科技接手过的应用性能工单里,“内存只涨不跌"十有八九是这两本账没对上——账本理清,问题就从玄学变回了工程。

企业存储选型参考|贵州诚鑫致达

小团队起步上手 NAS,群晖机型参考:DS425+ · DS224+ · DS124。需要选型建议或上门评估,搜「诚鑫致达」即可找到我们。