服务内存与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

分析步骤

  1. 检查Dominator Tree中的大对象
  2. 分析Leak Suspects报告
  3. 验证对象引用链是否合理

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(/* 处理逻辑 */);

七、预防措施

  1. 监控体系搭建

    • 部署Prometheus+Grafana监控集群
    • 配置JVM参数 -XX:+HeapDumpOnOutOfMemoryError
    • 设置APM埋点监控关键业务指标
  2. 容量规划

    # 预估容器内存需求
    JVM堆内存 = (对象数 × 对象大小) × 1.5
    容器内存 = JVM堆内存 × 2.5
    
  3. 自动化运维

    # 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)进行全链路分析。