4

我有一个 Java 应用程序,大部分时间都在消耗 100% 的 CPU(如 cacti 和 top 监控所示)。我们启动了 YourKit(它确认了 CPU 资源问题),它在 15% 的时间里将 java.net.SocketInputStream.read(byte[], int, int) 识别为最大的热点。我相信他们没有准确地测量像 SocketInputStream.read 这样执行阻塞 IO 的方法的 CPU 时间。

还有 6 个其他已确定的热点,但它们占 CPU 时间总和的不到 20%。都在 5%-1% 的范围内。

所以我知道我有问题,我可以看到问题,YourKit 也可以,但我离确定实际问题还差得远。

我对使用分析器很陌生,很可能会遗漏一些东西。有任何想法吗?

编辑:肖恩对使用系统内置的工具提出了一个很好的观点。如果我使用 top 和 shift+h 查看线程,它会显示 7-15 个线程,并且 CPU 利用率会跳跃。我不相信这是导致问题的任何一个线程,而是每个线程在某个时间执行的一段代码。

4

5 回答 5

3

如果可以的话,我建议在 Solaris 机器上运行它。如果您没有 Solaris 机器,请考虑设置一个运行 Open Solaris 的虚拟机。

Solaris 提供了一个名为prstat的工具

prstat 的工作方式与大多数人熟悉的 top 非常相似。重要的区别是 prstat 可以为您分解进程并显示进程中的每个线程。

对于您的情况,用法是 prstat -L 0 1

与线程转储配对(首选在脚本中执行此操作),您可以将 LWPID 匹配在一起,以准确找到哪个线程是 CPU hog。

这是一个功能示例(我创建了一个小应用程序,用于 poc 的大循环)

Standard Top 将显示如下内容

 PID USERNAME NLWP PRI NICE  SIZE   RES STATE    TIME    CPU COMMAND
  924 username   10  59    0   31M   11M run      0:53 36.02% java

然后使用 prstat 使用了如下命令

 prstat -L 0 1 | grep java > /export/home/username/Desktop/output.txt

以及 prstat 的输出

PID USERNAME  SIZE   RSS STATE  PRI NICE      TIME  CPU PROCESS/LWPID    
924 username   31M   10M run     30    0   0:00:09  35% java/10
924 username   31M   10M sleep   59    0   0:00:00 0.8% java/3
924 username   31M   10M sleep   59    0   0:00:00 0.6% java/2
924 username   31M   10M sleep   59    0   0:00:00 0.3% java/1

这可能看起来与顶部没有太大不同,但是如果您注意到数据的右侧,则 PROCESS/LWPID 会告诉您 java 进程中消耗 CPU 的确切线程。以轻量级进程 id (lwpid) 10 运行的线程正在消耗 35% 的 CPU。正如我之前提到的,如果你将它与线程转储配对,你可以找到确切的线程。就我而言,这是线程转储的相关部分

"Thread-0" prio=3 tid=0x08173800 nid=0xa runnable [0xc60fc000..0xc60fcae0]
   java.lang.Thread.State: RUNNABLE
    at java.util.Random.next(Random.java:139)
    at java.util.Random.nextInt(Random.java:189)
    at ConsumerThread.run(ConsumerThread.java:13)

在线程的最上面一行,nid可以与 LWPID 匹配。nid=0xa(从十六进制转换为 10 十进制)

如果您可以将 prstat 和线程转储命令放在脚本中并在 CPU 使用率较高的情况下运行 4-5 次,您将开始看到模式并能够通过这种方式确定导致 CPU 使用率过高的原因。

在我的时代,我已经看到了从长时间运行 gc 时间到错误配置 LDAP 连接的结果。玩得开心 :)

于 2011-07-29T04:46:34.850 回答
2

你可能有统一的慢代码

于 2011-07-29T03:13:24.553 回答
1

我会打开内存跟踪和 cpu 分析并再次查看 cpu 分析器。这将显示要优化的不同区域。

当您说它使用 100% 的 CPU 时,您可以查看它是在用户空间还是系统/内核空间中。例如顶部。探查器不会显示内核空间中使用的 cpu。

你有多少线程?如果您有足够的空闲线程,则只需在它们之间切换即可获得超过 100% 的 CPU。(你必须有成千上万)

像类似的答案一样,您的应用程序很可能有很多开销,例如读取套接字、线程之间的交换、执行 GC,它并没有做太多的实际工作。剖析器不太擅长处理开销。

于 2011-07-29T06:40:29.263 回答
1

jvisualvm分析器是比较方便的替代方案它包含在 JDK 中。

于 2011-07-29T03:08:46.083 回答
0

一种可能是你的 JVM 没有足够的内存,所以它一直在做 GC。

于 2011-07-29T03:40:22.753 回答