Java应用程序中的高CPU利用率 - 为什么?

时间:2013-04-04 12:38:11

标签: java multithreading performance web-applications cpu-usage

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

所以要调查

我使用Thread Dump来查找正在执行的线程。在'RUNNABLE'状态中找到了几个线程,在少数其他状态中找到了一些线程。在重复的线程转储中,我确实看到一些始终存在于'RUNNABLE'状态的线程。所以,他们似乎是罪魁祸首。

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

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

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

7 个答案:

答案 0 :(得分:40)

如果您的设置中的探查器不适用,您可以尝试按照this post中的步骤识别该断言。

基本上,有三个步骤:

  1. 运行top -H并获取具有最高CPU的线程的PID。
  2. 将PID转换为十六进制。
  3. 在线程转储中查找具有匹配HEX PID的线程。

答案 1 :(得分:12)

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

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

您应该检查应用程序中是否存在可能的内存泄漏并且已经为内存配置得很好(请查看-Xmx参数,请参阅What does Java option -Xmx stand for?

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

答案 2 :(得分:2)

在这些峰值CPU时间内,用户负载如何?你说这是一个基于Web的应用程序,所以想到的罪魁祸首就是内存利用率问题。例如,如果你在会话中存储了很多东西,并且会话数量足够高,那么app服务器就会开始吵架。这也是GC根据您使用的方案可能会使事情变得更糟的情况。有关应用程序和服务器配置的更多信息将有助于指出更多调试思路。

答案 3 :(得分:1)

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

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

  2. 如果睡觉正确的事情,你是否在适当的时间内睡觉 - 这通常是一个非常难以回答的问题。

  3. 多线程设计中最常见的错误是相信在等待某事发生时你需要做的就是检查它并在紧密的循环中休眠一会儿。这很少是一种有效的解决方案 - 你应该总是尝试wait来发生这种情况。

    第二个最常见的问题是循环不睡觉。这更糟糕,并且不容易追踪。

答案 4 :(得分:1)

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

表示当前正在运行的主线程......

"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)**

答案 5 :(得分: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 也可以使用浏览器打开,简而言之,stack trace中元素的宽度指定了相对包含执行流程的线程转储数量。

很少有其他方法可以生成它们

  • 通过将 -XX:+PreserveFramePointer 作为 JVM 选项引入 here
  • 将 async-profiler 与 -XX:+UnlockDiagnosticVMOptions -XX:+DebugNonSafepoints 结合使用here

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

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

答案 6 :(得分: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。