服务内存与CPU异常占用排查全流程指南
一、初步定位异常进程
1.1 系统级监控
# 查看整体资源使用情况
top -H -p <PID> # 按线程查看CPU占用
free -h # 内存分布分析
iostat -x 1 # 磁盘I/O监控
vmstat 1 5 # 虚拟内存统计
关键指标:
- CPU Load Average > CPU核心数 × 0.7
- 内存Swap使用率 > 20%
- 磁盘await时间 > 50ms
1.2 进程级定位
# 查找高CPU进程
ps -eo pid,ppid,cmd,%cpu,%mem --sort=-%cpu | head -n 10
# 查找高内存进程
ps -eo pid,ppid,cmd,%mem --sort=-%mem | head -n 10
典型场景:
- 某进程CPU持续>90%且无波动 → 可能为死循环
- 内存持续增长且不释放 → 内存泄漏
二、Java进程深度分析
2.1 JVM状态检查
# 查看JVM进程信息
jps -lvm
# 堆内存分析
jstat -gcutil <PID> 1000 20 | awk '/^ / {print $13,$14,$15}'
# 线程堆栈分析
jstack -l <PID> > thread_dump.log
关键分析点:
- Full GC频率 > 1次/分钟
- Eden区使用率持续>80%
- 非堆内存(Metaspace)持续增长
2.2 线程级问题定位
# 使用Arthas动态监控
java -jar arthas-boot.jar
dashboard # 实时监控面板
thread -n 5 # 查看最忙线程
jad <类名> # 反编译代码
典型线程状态:
RUNNABLE状态线程占比>70%- 存在大量
BLOCKED线程 - 线程堆栈出现重复代码片段
三、内存泄漏排查
3.1 堆内存分析
# 生成堆转储文件
jmap -dump:format=b,file=heap.hprof <PID>
# 使用MAT分析
./MemoryAnalyzer.sh heap.hprof
分析步骤:
- 检查Dominator Tree中的大对象
- 分析Leak Suspects报告
- 验证对象引用链是否合理
3.2 Native内存泄漏
# 查看进程内存映射
pmap -x <PID> | sort -nrk3 | head -n 20
# 检查glibc缓存
gdb -batch -ex 'call malloc_stats()' -p <PID>
# 使用tcmalloc检测
LD_PRELOAD=/usr/lib/libtcmalloc.so.4 ./your_app
典型问题:
- GZIPInputStream未关闭导致native内存堆积
- JNI调用未释放本地引用
四、CPU高占用排查
4.1 线程级分析
# 查看线程CPU使用
ps -eLf | grep <PID> | sort -k3 -r | head -n 10
# 使用perf分析热点代码
perf top -p <PID> -g -- sleep 10
典型场景:
- 正则表达式处理超时
- 大数据量排序/聚合计算
- 频繁的GC操作(YGC>100次/分钟)
4.2 JIT编译分析
# 查看JIT编译日志
-XX:+UnlockDiagnosticVMOptions -XX:+LogCompilation
# 分析热点方法
jcmd <PID> CompilerInfo
优化方向:
- 避免在循环中进行复杂计算
- 使用缓存减少重复计算
- 优化算法时间复杂度
五、系统级问题排查
5.1 I/O瓶颈分析
# 查看磁盘I/O
iotop -oP
# 查看网络连接
ss -s | grep -E 'Total|ESTAB'
# 检查文件描述符
lsof -p <PID> | awk '{print $9}' | sort | uniq -c | sort -nr
5.2 锁竞争分析
# 使用jstack分析锁状态
jstack -l <PID> | grep -A 10 'BLOCKED'
# 使用Async-Profiler分析锁竞争
./async-profiler.sh start --lock <PID>
六、典型问题处理方案
6.1 内存泄漏处理
// 修复未关闭的资源
try (InputStream is = new FileInputStream(file)) {
// 业务逻辑
} catch (IOException e) {
// 异常处理
}
// 优化缓存策略
Cache<String, Object> cache = CacheBuilder.newBuilder()
.maximumSize(10000)
.expireAfterWrite(10, TimeUnit.MINUTES)
.build();
6.2 CPU优化方案
// 避免正则表达式热点
String processed = text.replaceAll("pattern", "replacement");
// 改用预编译模式
Pattern pattern = Pattern.compile("pattern");
Matcher matcher = pattern.matcher(text);
while (matcher.find()) {
// 处理匹配结果
}
// 使用并行流加速计算
list.parallelStream().forEach(/* 处理逻辑 */);
七、预防措施
-
监控体系搭建:
- 部署Prometheus+Grafana监控集群
- 配置JVM参数
-XX:+HeapDumpOnOutOfMemoryError - 设置APM埋点监控关键业务指标
-
容量规划:
# 预估容器内存需求 JVM堆内存 = (对象数 × 对象大小) × 1.5 容器内存 = JVM堆内存 × 2.5 -
自动化运维:
# Kubernetes HPA配置示例 apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler spec: minReplicas: 2 maxReplicas: 10 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 70
八、排查流程图
graph TD
A[发现异常] --> B{资源类型?}
B -->|CPU| C[线程分析]
B -->|内存| D[堆内存分析]
C --> E[Arthas监控]
C --> F[perf分析]
D --> G[堆转储分析]
D --> H[NMT跟踪]
E --> I[定位热点代码]
F --> J[系统调用分析]
G --> K[内存泄漏验证]
H --> L[Native内存追踪]
I --> M[代码优化]
J --> N[锁竞争优化]
K --> O[对象引用优化]
L --> P[JNI代码审查]
通过上述流程,可系统化解决80%以上的性能问题。对于复杂场景,建议结合APM工具(如SkyWalking)和分布式追踪(如Zipkin)进行全链路分析。