公司新上线一个后台管理服务,部署到测试环境的Tomcat后,页面响应越来越慢,后台日志里隔三差五就冒出java.lang.OutOfMemoryError: Java heap space。重启Tomcat能撑一两个小时,接着又卡死——这哪是业务问题,分明是堆内存没配对。
为啥堆内存总出事?
Tomcat本身是个Java进程,所有Web应用(比如你的Spring Boot打包成war丢进去)都跑在它的JVM里。堆内存就是JVM里专门存对象的地方。配小了,对象一多就溢出;配太大,GC停顿时间拉长,请求卡在那儿不动;更麻烦的是,32位系统或某些老版本JDK还有堆上限限制,硬塞4G可能根本起不来。
去哪改?认准catalina.sh或catalina.bat
Linux下进$CATALINA_HOME/bin/,打开catalina.sh;Windows就找catalina.bat。别去改setenv.sh(万一不存在还得自己建),也别碰server.xml——那玩意儿管不了JVM参数。
找到类似这样的行(通常在注释块下面):
# OS specific support. $var _must_ be set to either true or false.在这附近加一行(注意位置:必须在exec "$PRGDIR"/"$_RUNJAVA"之前,否则不生效):
export JAVA_OPTS="-Xms512m -Xmx2g -XX:+UseG1GC"Windows对应写法:
set JAVA_OPTS=-Xms512m -Xmx2g -XX:+UseG1GC参数咋选?记住三个数
-Xms:JVM启动时直接分配的堆大小,建议和-Xmx设成一样,避免运行中动态扩容导致STW暂停;
-Xmx:堆最大值,别超物理内存的75%,比如服务器有8G内存,Tomcat独占的话,-Xmx设到4g比较稳妥;
-XX:+UseG1GC:JDK8u20以后推荐用G1垃圾回收器,大堆下比Parallel更可控。
别瞎抄网上“-Xmx4g”——你服务器总共才4G内存?留点给操作系统、其他进程和Metaspace,不然Swap狂刷,比OOM还难查。
验证有没有生效?
启动Tomcat后,执行:ps -ef | grep tomcat(Linux)或任务管理器看Java进程命令行参数。
看到类似-Xms512m -Xmx2g就对了。再进Tomcat管理页(http://localhost:8080/manager/status),右上角「JVM信息」里也能看到当前堆已用/最大值。
配完还是OOM?试试加个监控开关
在JAVA_OPTS里补上这两句,下次OOM时会自动生成堆转储文件(heap dump),方便用VisualVM或JProfiler分析:
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/opt/tomcat/logs/heap.hprof路径记得提前创建好目录并赋权,不然dump写不进去,日志里连错都不报,纯静默失败。
有次线上遇到一个定时任务每小时扫10万条订单,开发说“逻辑很简单”,结果一跑就OOM。抓了heap dump一看,List里塞了几万个未关闭的数据库连接对象——堆内存配再大也没用,得修代码。所以配参数只是第一步,它暴露问题,但不代替排查。