Tomcat OOM触发自动重启失效问题求助
排查Tomcat -XX:OnOutOfMemoryError参数失效问题
以下是几个核心排查方向,按优先级逐一验证:
1. 修正-XX:OnOutOfMemoryError的参数格式
你的setenv.sh中该参数使用单引号包裹命令,在shell环境下会导致参数解析异常,JVM无法正确识别要执行的命令序列。正确写法应去掉单引号,改用双引号(或直接不包裹,双引号可避免空格等特殊字符解析问题):
JAVA_OPTS="$JAVA_OPTS -Djava.awt.headless=true -Dfile.encoding=UTF-8 -Djava.security.egd=file:/dev/./urandom -server -Xms1536m -Xmx1536m -XX:NewSize=1536m -XX:MaxNewSize=1536m -XX:OnOutOfMemoryError=pkill java;/root/restart.sh -XX:+DisableExplicitGC -DecadiaConsoleLogLevel=off"
更稳妥的方式是转义分号,避免被shell提前解析:
JAVA_OPTS="$JAVA_OPTS ... -XX:OnOutOfMemoryError=pkill\ java\;/root/restart.sh ..."
2. 检查脚本权限与访问性
- 确保
/root/restart.sh拥有执行权限:执行chmod +x /root/restart.sh - Tomcat默认以
tomcat用户运行,/root目录对非root用户无访问权限,会导致JVM触发OOM时无法读取脚本。建议将脚本移至Tomcat有权限访问的目录(如/usr/local/tomcat/bin/),并修改所属用户:mv /root/restart.sh /usr/local/tomcat/bin/ chown tomcat:tomcat /usr/local/tomcat/bin/restart.sh tomcat用户默认无systemctl执行权限,会导致脚本中systemctl restart命令失败。可通过添加sudo权限解决:
编辑/etc/sudoers文件,添加一行:
然后修改脚本命令为tomcat ALL=(ALL) NOPASSWD: /bin/systemctl restart tomcat9.servicesudo systemctl restart tomcat9.service
3. 验证JVM参数是否生效
重启Tomcat后,查看进程启动参数,确认-XX:OnOutOfMemoryError是否被正确加载:
ps aux | grep tomcat | grep -v grep
若参数不存在,说明setenv.sh未被Tomcat启动脚本加载。检查setenv.sh是否放在Tomcat的bin目录下,且拥有可读权限:
chmod +r /usr/local/tomcat/bin/setenv.sh
4. 优化重启脚本逻辑
你的脚本先执行pkill java再判断Tomcat状态,存在时序问题:pkill执行后Tomcat进程才会退出,此时systemctl可能还未将进程标记为failed,导致脚本跳过重启。可简化逻辑,直接执行重启命令(systemctl restart会自动处理进程状态):
#!/bin/bash echo "$(date) Triggering Tomcat restart due to OOM" >> /var/log/tomcat_oom_restart.log sudo systemctl restart tomcat9.service
添加日志输出,方便后续排查执行情况。
5. 模拟OOM时的环境验证
手动触发OOM测试时,确保stressapptest确实耗尽了Tomcat的堆内存(你的Xmx设置为1536m,需确保压测分配内存超过该值)。也可用简单Java程序模拟OOM:
import java.util.ArrayList; import java.util.List; public class OOMTest { public static void main(String[] args) { List<byte[]> list = new ArrayList<>(); while (true) { list.add(new byte[1024 * 1024]); } } }
编译后在Tomcat运行环境下执行,观察是否触发脚本执行。
内容的提问来源于stack exchange,提问作者user11700065
相关产品推荐
相关产品推荐

