常见原因:死循环 / 锁竞争 / 频繁GC / 大量计算

  1. 查看整体进程占用资源情况

    top
    
    • 默认每 3 秒刷新一次
    • 可按 P 排序(CPU 占用)或 M 排序(内存占用)
    • 可改刷新间隔:
    top -d 1   # 每秒刷新
    top -c     # 显示完整命令行
    
    • 找到占用过高的 Java 进程,例如 pid=22714, 12406

    • 列出 Java 进程信息

      ps aux | grep java --color   # 高亮显示 java 进程
      jps                          # 显示 Java 进程及类名
      

Java 进程可能是某个线程导致高 CPU,需单独监控线程:

  1. top 查看线程

    top -H -p <pid> # 进程PID
    
    • -H 显示线程
    • 在 top 界面:
      • 按大写 P 按 CPU 排序
      • 按大写 M 按内存排序
    • 示例:
    top -p 22714 -H
    
    • 其他查看线程命令:
    ps -Lfp <pid>           # 查看 pid 下所有线程
    ps -mp <pid> -o THREAD,tid,time   # 显示线程号、线程ID、CPU时间
    ps -T -p <pid>           # SID 列线程ID,CMD 列线程名
    
    • 注意:
      • PR 表示优先级,值越小优先级越高
      • THREAD / tid 可用于后续堆栈分析

  1. 线程 ID 转十六进制

    printf "%x\n" <tid>  # tid线程
    printf '%x' <tid>
    printf '0x%x' <tid>
    
    • 示例:
    printf "%x\n" 156643
    # 输出 3d30 # 十六进制 线程号
    
  2. 查看线程堆栈

    jstack -l <pid> 
    jstack <pid> | grep -a <hex_tid>
    jstack <pid> |grep hex_tid -A 30 -C5 –color
    jstack pid > 1.txt
    

    用top出来的 进程号 ,而不是top -H出来的线程号

    • 示例:

      jstack 22714 | grep -a 3d30
      

      在这里插入图片描述

      • “Attach Listener”: 代表线程名。
      • #15:代表线程的唯一标识。
      • daemon:代表后台守护线程。
      • prio: 线程优先级。
      • os_prio: 操作系统层面的线程优先级。
      • tid:JVM分配的线程号。
      • nid:操作系统层面的线程号,显示格式为16进制。
    • 或直接查看整个线程堆栈:

      jstack 22714 > thread.log
      

      在这里插入图片描述

  3. 导出dump文件

    • 导出

      # 导出指定进程的完整堆快照(包含所有对象,无论是否存活)
      jmap -dump:format=b,file=<快照文件名>.dump <Java进程PID>
      
      # 仅导出存活对象的堆快照(过滤已死亡对象,文件更小,推荐)
      jmap -dump:live,format=b,file=<快照文件名>.dump <Java进程PID>
      
      参数 作用
      format=b 指定快照格式为二进制(唯一支持格式,不可省略)
      file=<文件名>.dump 定义快照输出路径和文件名(建议包含时间戳,便于区分版本)
      live 可选参数,仅导出 “存活对象”(减少快照文件大小,避免无效数据干扰分析)
      <Java进程PID> 目标 Java 进程的 ID(通过 jpsps aux | grep java 获取)
    • 使用jdk自带的jvisualvm.exe分析快照

      • “类” 标签页:查看对象数量与大小
      • “实例” 标签页:查看具体对象详情
      • “OQL 查询”:精准筛选对象
    • 通过jhat命令生成html通过localhost:7000查看

      # -J-Xmx2g 是给 jhat 自身分配堆内存(建议设为快照大小的 1.5 倍)
      jhat -J-Xmx2g <快照文件名>.dump
      # 解析 1GB 的快照,给 jhat 分配 2GB 堆内存
      jhat -J-Xmx2g 20240520_myapp_heap.dump
      

    注意:给线程起一个好名字非常重要,否则你刀磨的再快,命令玩儿的再溜,依然砍不到人。

  4. 分析dump文件

    a. 死锁,Deadlock
    b. 执行中,Runnable
    c. 等待资源,Waiting on condition
    d. 等待获取监视器,Waiting on monitor entry
    e. 暂停,Suspended
    f. 对象等待中,Object.wait()或TIMED_WAITING
    g. 阻塞,Blocked
    h. 停止,Parked


四、排查流程总结

  1. topps → 找到高 CPU Java 进程
  2. top -H -p <pid>ps -Lfp <pid> → 找到高 CPU 线程
  3. printf "%x\n" <tid> → 转线程 ID 为十六进制
  4. jstack <pid> → 查看线程堆栈
  5. 分析代码、优化或修复

strace 命令

# 进程PID
strace -o out.txt -p pid # 可以查看某pid的执行过程并记录到out.txt

💡 Tips

  • 多次堆栈采样可确认是短暂峰值还是持续高 CPU
  • 可以结合 perfasync-profiler 做更深度分析
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐