Java CPU 资源过高故障排查与修复报告
一、故障现象指标状态CPU 占用150%单进程多核持续高位内存5~9% 持续增长进程 PID频繁变化每分钟都不同应用可用性间歇性不可用初始连接时发现 Java 进程 PID 多次变化2623 → 4804 → 6245 → 7275 → 8580...初步判断进程在反复重启。二、排查过程2.1 确认进程状态ps -eo pid,user,pcpu,pmem,comm | grep java输出示例PID USER %CPU %MEM COMMAND 6245 sprixin 130 9.8 java关键发现进程 CPU 130%PID 约每 60~90 秒变化一次。2.2 线程级 CPU 采样/proc sleep 差值法# Round 1: 采集 /proc/[pid]/task/[tid]/stat 中的 utime for tid in $(ls /proc/$pid/task/); do awk {print $1,$14,$2} /proc/$pid/task/$tid/stat done sleep 3 # Round 2: 再次采集计算差值 (CLK_TCK100, 3s300 jiffies)结果TOP 2 线程消耗了 80% CPUTIDCPU%线程名状态624682.33%mainRUNNABLE 625381.67%C2 CompilerThread0RUNNABLE (JIT)625430.00%C1 CompilerThread1RUNNABLE (JIT)6247-48~4%GC task threadsRUNNABLEC2/C1 编译器线程的高 CPU 是症状不是根因— JIT 在拼命编译热点方法。2.3 jstack 线程堆栈分析/home/sprixin/web/jdk1.7.0_79/bin/jstack 6245main 线程堆栈82% CPU 热点main #1 prio5 RUNNABLE at AnnotationParser.annotationForMap(AnnotationParser.java:303) at AnnotationParser.parseAnnotations2(AnnotationParser.java:120) at AnnotationParser.parseAnnotations(AnnotationParser.java:72) at Class.createAnnotationData(Class.java:3521) ← 创建注解数据 at Class.annotationData(Class.java:3510) at Class.createAnnotationData(Class.java:3526) ← 再次创建 at Class.annotationData(Class.java:3510) ← 循环! at Class.getDeclaredAnnotations(Class.java:3477) at AnnotationUtils.findAnnotation(...360) ← Spring 查找注解 at AnnotationUtils.findAnnotation(...338) → 循环回到 annotationData结论main 线程陷入Class.createAnnotationData↔Class.annotationData递归循环由 Spring 的AnnotationUtils.findAnnotation触发。2.4 jmap 堆内存分析/home/sprixin/web/jdk1.7.0_79/bin/jmap -histo 6245关键发现 — 注解相关的对象数量异常巨大类名实例数说明AnnotationUtils$AnnotationCacheKey48,505Spring 注解缓存 KEY[Ljava.lang.annotation.Annotation;48,985注解数组org.springframework.asm.Item38,402ASM 字节码 Itemorg.springframework.asm.Label32,032ASM 字节码 Labelorg.springframework.asm.Edge53,702ASM 字节码 Edge每次启动 Spring 都要为48K 个方法/类组合构建注解缓存消耗巨大 CPU。2.5 重启日志分析 — 找到根因grep Server startup /home/sprixin/web/apache-tomcat-7.0.69/logs/catalina.out发现30 次重启间隔60~90 秒14:13:47 Server startup 14:14:50 Server startup (63s 后) 14:15:50 Server startup (60s 后) 14:17:25 Server startup (95s 后) ... 14:55:45 Server startup 14:57:20 Server startup (持续循环)2.6 配置审查server.xml第 152 行Host namelocalhost appBasewebapps unpackWARstrue autoDeploytrue ← 罪魁祸首setenv.sh只有一行CATALINA_OPTS$CATALINA_OPTS -javaagent:$CATALINA_HOME/lib/sprixin-agent.jar # 没有任何 -Xms/-Xmx/-XX:MaxMetaspaceSizeJVM 默认内存无 -Xms/-Xmx区域容量已用使用率Metaspace19 MB18.2 MB95.76%Old Gen85 MB29 MB34.5%CCS2.2 MB2.0 MB89.9%三、根因分析根因链路autoDeploytrue ↓ 每次重启 → Tomcat 检测到 webapps 中 WAR 变化 → 自动重新部署 ↓ 重新部署 → Spring 重新初始化 → 扫描所有注解 (48K AnnotationCacheKey) ↓ 注解扫描消耗 130% CPU → Metaspace 95% 耗尽 (默认没有上限但提交不足) ↓ 启动未完成就触发某个失败 (OOME / 超时 / 健康检查) ↓ Tomcat 再次重启... 循环往复三层原因定位层级问题严重度类型触发层autoDeploytrue导致每次 WAR 变化自动重部署 致命配置错误放大层无 JVM 内存参数Metaspace 默认上限不足GC 频繁 致命配置缺失负载层Spring 扫描 48K 注解项 sprixin-agent.jar (Javassist) 加重字节码操作 严重应用设计次要DB 两张表缺失 (hdralarmbase20260729,software_updates) 警告应用 Bug四、修复方案与执行4.1 修改setenv.sh— 添加 JVM 内存参数路径:/home/sprixin/web/apache-tomcat-7.0.69/bin/setenv.sh修改前:CATALINA_OPTS$CATALINA_OPTS -javaagent:$CATALINA_HOME/lib/sprixin-agent.jar修改后:CATALINA_OPTS$CATALINA_OPTS -javaagent:$CATALINA_HOME/lib/sprixin-agent.jar ​ # JVM memory settings (added by fix script) CATALINA_OPTS$CATALINA_OPTS -Xms512m -Xmx1024m CATALINA_OPTS$CATALINA_OPTS -XX:MaxMetaspaceSize256m CATALINA_OPTS$CATALINA_OPTS -XX:UseParallelGC CATALINA_OPTS$CATALINA_OPTS -XX:DisableExplicitGC ​ # GC logging for future diagnosis CATALINA_OPTS$CATALINA_OPTS -XX:PrintGCDetails CATALINA_OPTS$CATALINA_OPTS -XX:PrintGCDateStamps CATALINA_OPTS$CATALINA_OPTS -Xloggc:$CATALINA_HOME/logs/gc.log参数说明: 系统内存 7.8GB-Xms512m -Xmx1024m给堆预留充足空间-XX:MaxMetaspaceSize256m解决注解扫描时 Metaspace 不足问题GC 日志便于后续诊断。4.2 修改server.xml— 关闭自动部署路径:/home/sprixin/web/apache-tomcat-7.0.69/conf/server.xml第 152 行修改:!-- 修改前 -- Host namelocalhost appBasewebapps unpackWARstrue autoDeploytrue ​ !-- 修改后 -- Host namelocalhost appBasewebapps unpackWARstrue autoDeployfalse 关闭autoDeploy阻止 Tomcat 自动检测 webapps 目录变化并重新部署这是打破重启循环的关键一步。4.3 清理与重启# 1. 杀掉所有 Java 进程 kill -9 all-java-pids ​ # 2. 清理 Tomcat 工作目录 rm -rf /home/sprixin/web/apache-tomcat-7.0.69/work/Catalina/localhost/SPPP-web ​ # 3. 单实例启动 /home/sprixin/web/apache-tomcat-7.0.69/bin/startup.sh五、验证结果5.1 启动过程监控时间CPU进程数状态T10s138%1annotation scanning...T20s132%1annotation scanning...T30s133%1annotation scanning...T40s144%1annotation scanning...T50s143%1STARTUP COMPLETE✅启动耗时约50 秒注解扫描完成后 main 线程进入ServerSocket.accept等待连接。5.2 稳定后状态对比指标修复前修复后改善CPU150%28.5%↓ 80%进程数1~2混乱1稳定正常重启间隔60~90 秒7 分钟 无重启∞HTTP 状态间歇 500200 OK正常Metaspace19MB / 95.76%82MB / 97.8%上限 256MB有余量PID 稳定性每分钟变化已运行 7 分钟(PID 15190)稳定5.3 线程状态修复后main → ServerSocket.accept() ← 正常等待连接 Acceptor → NIO accept ← 正常 Poller → NIO poll ← 正常 C1/C2 Compiler → 运行中 ← JIT 优化启动后逐渐空闲 Quartz ×10 → Object.wait() ← 空闲等待所有线程状态正常无死锁无 BLOCKED 线程。六、待处理问题问题说明优先级建议davinci.hdralarmbase20260729表缺失按日期生成的告警表应用代码中存在引用但未创建 中检查是否有定时建表脚本未运行davinci.software_updates表缺失软件更新表应用启动时查询失败 中补充建表 DDLsprixin-agent.jar(Javassist)启动时对每个类做字节码增强加重启动负载 低建议 review 其必要性GC 日志已开启-Xloggc 信息路径:logs/gc.log七、关键服务器信息项目值服务器 IP10.64.14.42操作系统CentOS 7, Linux 3.10.0-1160.el7.x86_64系统内存7.8 GBJava 版本1.8.0_181-b13 (Oracle)Java 路径/home/sprixin/web/jdk1.7.0_79(目录名含 7实际是 JDK 8)Tomcat 版本Apache Tomcat/9.0.113Tomcat 路径/home/sprixin/web/apache-tomcat-7.0.69(目录名含 7.0实际是 Tomcat 9)应用 WARSPPP-web.warHTTP 端口18080数据库MySQL 5.x (localhost:3306, davinci 库)八、诊断命令备忘# 线程 CPU 采样/proc 差值法 ps -eo pid,tid,pcpu,comm -p PID # 快速查看 for tid in $(ls /proc/PID/task/); do awk {print $1,$14,$2} /proc/PID/task/$tid/stat done ​ # 线程堆栈 /home/sprixin/web/jdk1.7.0_79/bin/jstack PID ​ # 堆内存直方图 /home/sprixin/web/jdk1.7.0_79/bin/jmap -histo PID ​ # GC 统计 /home/sprixin/web/jdk1.7.0_79/bin/jstat -gcutil PID 1000 ​ # 查看 JVM 启动参数 cat /proc/PID/cmdline | tr \0 \n ​ # 重启历史 grep Server startup /home/sprixin/web/apache-tomcat-7.0.69/logs/catalina.out九、总结此次 Java CPU 150% 故障的根本原因是 TomcatautoDeploytrue与未配置 JVM 内存参数共同导致的无限重启循环。两个简单的配置修改就解决了问题server.xml:autoDeploytrue→falsesetenv.sh: 添加-Xms512m -Xmx1024m -XX:MaxMetaspaceSize256m修复后 CPU 从150% 降至 28%应用稳定运行不再重启。经验教训: 生产环境 Tomcat 应关闭autoDeploy始终为 JVM 显式设置堆和元空间大小GC 日志对于诊断内存问题至关重要。

相关新闻

最新新闻

日新闻

周新闻

月新闻