Tomcat 8.5部署4个WAR包触发GC overhead limit exceeded错误求助
Tomcat 8.5部署多WAR包触发GC Overhead Limit Exceeded问题解决
问题分析
部署4个Groovy+AngularJS开发的WAR包时,任意2个正常启动,第3个启动就抛出java.lang.OutOfMemoryError: GC overhead limit exceeded,核心原因:
- JVM堆内存分配不足,多个应用启动后内存占用超出阈值,GC无法有效回收足够内存;
- 你新增多个Service的操作无法解决问题——所有Service共享同一个Tomcat进程的JVM堆内存,内存占用是累加的,并没有扩展可用内存空间。
解决方案
1. 调整JVM堆内存参数
修改Tomcat启动脚本(Linux为catalina.sh,Windows为catalina.bat),在JAVA_OPTS中增加堆内存和元空间配置:
# Linux示例,添加到catalina.sh开头 export JAVA_OPTS="-Xms2G -Xmx4G -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=512M -XX:+UseG1GC"
:: Windows示例,添加到catalina.bat开头 set JAVA_OPTS=-Xms2G -Xmx4G -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=512M -XX:+UseG1GC
-Xms2G:初始堆内存2GB,避免频繁扩容消耗资源;-Xmx4G:最大堆内存4GB,可根据服务器物理内存调整(建议不超过物理内存的70%);Metaspace参数:Groovy会动态生成大量类文件,需要足够的元空间存储类元数据;-XX:+UseG1GC:使用G1垃圾收集器,适合大堆内存场景,提升GC效率。
2. 优化Tomcat线程池配置
默认Connector的线程配置可能过高,导致线程占用过多内存。给每个Connector配置共享线程池,减少线程数量:
在server.xml的Service节点外添加Executor配置,然后让所有Connector引用该线程池:
<!-- 全局共享线程池 --> <Executor name="sharedThreadPool" namePrefix="tomcat-exec-" maxThreads="200" minSpareThreads="25" maxIdleTime="60000"/> <!-- 修改每个Connector,添加executor引用 --> <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" maxParameterCount="1000" executor="sharedThreadPool"/>
maxThreads:最大线程数,根据应用并发需求调整,避免设置过大;minSpareThreads:核心线程数,保持一定数量的空闲线程应对突发请求;maxIdleTime:空闲线程超时时间,自动回收闲置线程节省内存。
3. 排查应用内存泄漏
如果调大内存后问题复现,需排查应用本身的内存泄漏:
- 使用JDK自带的
jmap命令生成堆转储文件:jmap -dump:format=b,file=heapdump.hprof <Tomcat进程ID> - 用
jvisualvm或MAT(Memory Analyzer Tool)分析堆转储,定位占用内存过高的对象:- 重点检查Groovy动态生成的类是否未被正确回收;
- 检查代码中的静态引用、ThreadLocal是否存在未清理的对象;
- 同步排查AngularJS前端的内存泄漏(如未销毁的监听、DOM引用)。
4. 拆分多实例部署
若上述方案无法解决,可将4个WAR包拆分到多个独立Tomcat实例中部署:
- 复制Tomcat目录,每个实例配置不同的端口(Connector、Shutdown端口);
- 每个实例分配独立的JVM堆内存,避免单进程内存过载。
内容的提问来源于stack exchange,提问作者vineet agrawal
相关产品推荐
相关产品推荐

