53

我有一个 Java 应用程序(基于 Web),它有时会在几个小时内显示出非常高的 CPU 利用率(几乎 90%)。LinuxTOP命令显示了这一点。在应用程序重新启动时,问题就消失了。

所以要调查

我使用 Thread Dump 来查找线程在做什么。有几个线程处于'RUNNABLE'状态,一些处于其他状态。在进行重复的线程转储时,我确实看到了一些始终处于'RUNNABLE'状态的线程。所以,他们似乎是罪魁祸首。

但我无法确定,哪个线程占用了 CPU 或进入了无限循环(从而导致高 CPU 利用率)。

日志不一定有帮助,因为有问题的代码可能没有记录任何内容。

如何调查 - 应用程序的哪个部分或哪个线程导致 CPU 使用率高?- 还有其他想法吗?

4

7 回答 7

55

如果分析器不适用于您的设置,您可以尝试按照本文中的步骤识别线程。

基本上,分为三个步骤:

  1. 运行top -H并获取 CPU 最高的线程的 PID。
  2. 将PID转换为十六进制。
  3. 在您的线程转储中查找具有匹配 HEX PID 的线程。
于 2013-04-04T15:45:52.510 回答
20

您可能是垃圾收集问题的受害者。

当您的应用程序需要内存并且配置为使用的内存不足时,垃圾收集器将经常运行,这会消耗大量 CPU 周期。如果它无法收集任何东西,您的内存将保持低位,因此它将一次又一次地运行。当您重新部署应用程序时,内存会被清除,垃圾收集不会超出要求,因此 CPU 利用率会一直保持在较低水平,直到它再次满为止。

您应该检查您的应用程序中没有可能的内存泄漏,并且它的内存配置良好(检查-Xmx参数,请参阅Java 选项 -Xmx 代表什么?

另外,您使用什么作为Web框架?JSF 非常依赖会话,消耗大量内存,最多考虑无状态!

于 2013-04-04T13:11:42.363 回答
5

在线程转储中,您可以找到如下所示的行号。

对于当前正在运行的主线程...

"main" #1 prio=5 os_prio=0 tid=0x0000000002120800 nid=0x13f4 runnable [0x0000000001d9f000]
   java.lang.Thread.State: **RUNNABLE**
    at java.io.FileOutputStream.writeBytes(Native Method)
    at java.io.FileOutputStream.write(FileOutputStream.java:313)
    at com.rana.samples.**HighCPUUtilization.main(HighCPUUtilization.java:17)**
于 2015-05-29T06:50:02.627 回答
2

在这些 CPU 高峰期,用户负载如何?你说这是一个基于 Web 的应用程序,所以想到的罪魁祸首是内存利用率问题。例如,如果您在会话中存储了很多东西,并且会话计数变得足够高,则应用服务器将开始颠簸。这也是 GC 可能会使事情变得更糟的情况,具体取决于您使用的方案。有关应用程序和服务器配置的更多信息将有助于指出更多调试想法。

于 2013-04-04T13:06:15.703 回答
1

火焰图有助于识别消耗最多 CPU 时间的执行路径。

简而言之,以下是生成火焰图的步骤

yum -y install perf

wget https://github.com/jvm-profiling-tools/async-profiler/releases/download/v1.8.3/async-profiler-1.8.3-linux-x64.tar.gz

tar -xvf async-profiler-1.8.3-linux-x64.tar.gz
chmod -R 777 async-profiler-1.8.3-linux-x64
cd async-profiler-1.8.3-linux-x64

echo 1 > /proc/sys/kernel/perf_event_paranoid
echo 0 > /proc/sys/kernel/kptr_restrict

JAVA_PID=`pgrep java`

./profiler.sh -d 30 $JAVA_PID -f flame-graph.svg

flame-graph.svg也可以使用浏览器打开,简而言之,堆栈跟踪中元素的宽度指定了相对包含执行流的线程转储的数量。

生成它们的其他方法很少

  • 通过引入此处-XX:+PreserveFramePointer描述的 JVM 选项
  • 如此处-XX:+UnlockDiagnosticVMOptions -XX:+DebugNonSafepoints所述使用 async-profiler

但是使用 async-profiler 而不提供任何选项虽然不是很准确,但可以在不更改正在运行的 Java 进程的情况下利用进程的 CPU 开销低。

他们的wiki提供了有关如何利用它的详细信息。更多关于火焰图的信息可以在这里找到

于 2021-02-20T14:34:59.403 回答
0

您的第一种方法应该是找到对Thread.sleep的所有引用并检查:

  1. 睡觉是正确的做法——如果可能的话,你应该使用某种等待机制——也许小心使用 aBlockingQueue会有所帮助。

  2. 如果睡觉正确的事情,那么你的睡眠时间是否正确——这通常是一个很难回答的问题。

多线程设计中最常见的错误是认为在等待某事发生时您需要做的就是检查它并在一个紧密的循环中休眠一段时间。这很少是一个有效的解决方案 - 您应该始终尝试wait以防万一。

第二个最常见的问题是在没有 sleep的情况下循环。这甚至更糟,而且不太容易追踪。

于 2013-04-04T12:48:10.597 回答
0

您没有将“linux”分配给问题,但您提到了“Linux top”。因此这可能会有所帮助:

使用 Linux 小工具 threadcpu 来识别使用线程最多的 cpu。它调用 jstack 来获取线程名称。通过管道中的“sort -n”,您可以获得按 CPU 使用情况排序的线程列表。

更多细节可以在这里找到: http ://www.tuxad.com/blog/archives/2018/10/01/threadcpu_-_show_cpu_usage_of_threads/index.html

如果您仍然需要更多详细信息,请创建线程转储或在线程上运行 strace。

于 2018-10-15T20:14:41.203 回答