java应用程序中的高CPU利用率-为啥?

Posted

技术标签:

【中文标题】java应用程序中的高CPU利用率-为啥?【英文标题】:High CPU Utilization in java application - why?java应用程序中的高CPU利用率-为什么? 【发布时间】:2013-03-26 12:56:44 【问题描述】:

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

所以要调查

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

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

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

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

【问题讨论】:

您是否已经尝试过探查器? 您的线程转储还应该显示在线程转储期间这些可运行线程在代码中的位置。你需要在你的代码中查看那里。 IIRC“可运行”线程可能正在等待 I/O 而不会占用 CPU,但现在还早,我还在喝咖啡。 andreapier> 虽然我可能无法在 Prod 环境中使用 Profiler,但 Profiler 会告诉哪个线程占用 CPU? 您是否在相似的代码行上看到了许多可运行文件?如果是这样,您可以通过公共行的线程转储吗? 【参考方案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中元素的宽度相对指定了包含执行流的thread dump的数量。

生成它们的方法很少

通过引入-XX:+PreserveFramePointer 作为JVM 选项,如here 所述 使用带有-XX:+UnlockDiagnosticVMOptions -XX:+DebugNonSafepoints 的异步分析器,如here 所述

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

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

【讨论】:

【参考方案2】:

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

基本上分为三个步骤:

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

【讨论】:

如何在 windows 上实现同样的功能? 链接已损坏。 web.archive.org/web/20190403090107/http://code.nomad-labs.com/…【参考方案3】:

您没有将“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。

【讨论】:

【参考方案4】:

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

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

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

【讨论】:

这个特定线程正在等待writeBytes OS 调用完成。它几乎不使用 CPU 周期。但一般方法是正确的 - 执行线程转储并查找正在执行计算的线程。【参考方案5】:

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

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

您应该检查您的应用程序中没有可能的内存泄漏,并且它的内存配置良好(检查-Xmx 参数,请参阅What does Java option -Xmx stand for?)

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

【讨论】:

stop the world gc(本质上就是你所指的)不能运行多线程。你会发现它会完全使用其中一个核心。 内存利用率似乎没问题,我正在看。在 Java Visual VM 中,我可以看到 GC (CPU) Activity 非常低。【参考方案6】:

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

【讨论】:

内存利用率似乎还可以。【参考方案7】:

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

    睡眠是正确的做法 - 如果可能,您应该使用某种等待机制 - 小心使用 BlockingQueue 可能会有所帮助。

    如果睡觉正确的做法,那么您的睡眠时间是否正确 - 这通常是一个很难回答的问题。

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

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

【讨论】:

以上是关于java应用程序中的高CPU利用率-为啥?的主要内容,如果未能解决你的问题,请参考以下文章

React-Native 中的高 CPU 使用率

SpriteKit 游戏中的高 CPU 使用率

为啥运行应用程序时 Eclipse CPU 使用率会增加?

Java程序CPU占用过高怎么解决

Angular CLI - ng serve - 来自节点进程的高 CPU 使用率

Esper 5.4 java进程CPU占用率高