怎样解决 CPU 100% 的问题

如何定位程序运行 CPU 占用率 100% 的问题!

模拟

启动两个线程 “Test-Thread-1” 和 “Test-Thread-2”,第一个线程会无限制消耗 CPU,第二个线程会一直休眠,代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
}
}
}, "Test-Thread-1").start();

new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
}
}
}, "Test-Thread-2").start();

使用命令 top 定位本地线程

当上述代码运行起来后,我们在命令行窗口输入 top 命令来显示当前系统的一些资源占用情况。如下图所示,最上面的红框里面的 “Tasks” 代表的是当前系统有多少个进程,而进程号为 3269 的进程的 CPU 占用率为 99.7%,由此我们可以认为这个进程就是我们刚刚运行起来的这个程序:

find_cpu100_pid

我们现在的 top 命令展示的是所有进程信息,现在在这个界面上按下 “Shift + h”,即大写的 “H” 按键,会切换到线程模式。如下图所示,系统当前有 879 个线程正在运行,而线程 ID 为 3301 的线程正在大量的消耗 CPU:

fidn_cpu100_thread_id

使用 jstack 定位 Java 线程

刚才找到的线程 ID 为 3301 ,这个 3301 对应的是本地线程的 ID,而非 Java 世界里面相应的线程 ID。因此我们就需要根据本地线程找到 Java 线程。

现在使用 jstack 3269 命令来 DUMP 当前线程堆栈,部分结果如下所示:

thread_dump

这里我们需要了解的是 3301 是十进制的 ID,Java 线程使用的是十六进制的 ID 来表示的,因此需要将 3301 转为十六进制,3301 的十六进制为 0xce5,由此我们便可以找到 “Test-Thread-1” 的线程的第 10 行代码处正在消耗 CPU。

至此,问题解决!

参考

推荐文章