CPU 占用 100% 排查及 jstack 命令详解

CPU 占用 100% 排查及 jstack 命令详解

在 Java 应用运行过程中,有时会遇到 CPU 占用率飙升至 100% 的情况,这会导致应用响应缓慢、甚至卡顿崩溃。本文将详细介绍 CPU 占用 100% 的排查方法,以及如何使用 jstack 命令定位问题根源。

一、CPU 占用 100% 的常见原因

  1. 死循环:代码中存在无限循环逻辑,导致线程一直占用 CPU 资源。

  2. 线程阻塞与竞争:大量线程竞争锁资源,频繁的上下文切换消耗 CPU。

  3. 频繁 GC:内存泄漏或不合理的内存配置导致垃圾回收机制频繁运行,占用大量 CPU。

  4. 复杂计算:应用中存在耗时的复杂计算操作,长时间占用 CPU。

二、CPU 占用 100% 的排查步骤

1. 定位占用高 CPU 的进程

首先需要找到导致 CPU 占用过高的 Java 进程 ID。可以使用top命令(Linux 系统):

top

在 top 命令界面中,按P键可以按 CPU 使用率排序,找到 CPU 占用率高的进程,记录其 PID(进程 ID)。

如果是 Windows 系统,可以使用任务管理器资源监视器查看进程的 CPU 占用情况,获取对应的进程 ID。

2. 定位进程中占用高 CPU 的线程

知道进程 ID 后,需要进一步定位该进程中占用 CPU 较高的线程。使用以下命令(Linux 系统):

top -Hp <进程PID>

该命令会显示指定进程下各个线程的 CPU 占用情况,同样按P键排序,记录占用 CPU 高的线程 TID(线程 ID,十进制)。

3. 将线程 ID 转换为十六进制

因为 jstack 命令输出的线程 ID 是十六进制的,所以需要将上一步得到的十进制线程 ID 转换为十六进制。可以使用printf命令:

printf "%x\n" <线程TID>

例如,线程 TID 为 1234,转换为十六进制的命令为:

printf "%x\n" 1234

输出结果为4d2

4. 使用 jstack 命令获取线程堆栈信息

jstack 命令用于生成 Java 虚拟机当前时刻的线程快照,通过分析快照可以了解线程的运行状态、是否阻塞等信息。基本语法:

jstack <进程PID> > thread_dump.txt

该命令会将线程堆栈信息输出到thread_dump.txt文件中。

为了更精准地定位高 CPU 线程,可结合线程的十六进制 ID 在输出文件中查找对应的线程信息:

jstack <进程PID> | grep <十六进制线程ID> -A 30

其中-A 30表示显示匹配行及后面 30 行的内容。

三、jstack 命令详解

1. 常用参数

  • -l:显示关于锁的附加信息,包括拥有的锁和等待的锁。
jstack -l <进程PID> > thread_dump_with_lock.txt
  • -F:当正常输出请求不被响应时,强制输出线程堆栈。
jstack -F <进程PID> > forced_thread_dump.txt
  • -m:混合输出 Java 线程和原生线程的堆栈信息,有助于排查原生代码问题。
jstack -m <进程PID> > mixed_thread_dump.txt

2. 线程状态解读

在 jstack 输出的线程堆栈信息中,线程状态是关键分析点:

  • RUNNABLE:线程正在运行或就绪,若该状态的线程长期占用高 CPU,可能存在死循环或耗时计算。

  • BLOCKED:线程处于阻塞状态,等待获取锁资源,过多此类线程可能存在锁竞争问题。

  • WAITING:线程处于等待状态,通常是调用了wait()join()等方法,需要其他线程唤醒。

  • TIMED_WAITING:线程处于限时等待状态,如调用了sleep(long)wait(long)等方法。

四、实战案例分析

假设通过上述步骤,发现一个线程长期处于RUNNABLE状态且 CPU 占用高,在thread_dump.txt中找到该线程的堆栈信息如下:

"Thread-0" prio=5 tid=0x00007f8b4a00a000 nid=0x4d2 runnable [0x00007f8b49f00000]
   java.lang.Thread.State: RUNNABLE
        at com.example.HighCpuDemo.infiniteLoop(HighCpuDemo.java:15)
        at com.example.HighCpuDemo.run(HighCpuDemo.java:10)
        at java.lang.Thread.run(Thread.java:748)

从堆栈信息可知,线程Thread-0HighCpuDemo.java的第 15 行执行infiniteLoop方法时处于运行状态,进一步查看代码发现该方法存在死循环,这就是导致 CPU 占用 100% 的原因。

posted @ 2025-08-06 16:22  王张慧  阅读(374)  评论(0)    收藏  举报