解决cpu应用Java负载过高的方法

The way to solve cpu load too high of Java application

今天发现我的服务器cpu负载过高,而且服务器只是运行一个Java应用

这是我的操作步骤。

  1. 我使用了 top 命令来查找应用程序的 pid。 pid 是 25713.

  2. 我使用 top -H -p 25713 命令找到一些使用最多 cpu 的 pid。比如25719 tomcat 20 0 10.6g 1.5g 13m R 97.8 4.7 314:35.22 java.

  3. 我使用 jstack -F 25713 命令将转储 info.Such 打印为 "Gang worker#4 (Parallel GC Threads)" os_prio=0 tid=0x00007f5f10021800 nid=0x6477 runnable

  4. 我从转储文件中搜索了 pid。然后我发现用了大部分cpu的pid都是"Gang worker#4 (Parallel GC Threads)" os_prio=0 tid=0x00007f5f10021800 nid=0x6477 runnable

  5. 我用了jstack命令后,cpu就正常了!

这是我的问题:

  1. 为什么 GC Threads 使 cpu 负载过高。
  2. 为什么我用了jstack命令后cpu就正常了

每次都比这一次多。

这里是一些正常的日志。2015-10-10T10:17:52.019+0800: 71128.973: [GC (Allocation Failure) 2015-10-10T10:17:52.019+0800: 71128.973: [ParNew: 309991K->206K(348416K), 0.0051145 secs] 616178K->306393K(1009920K), 0.0052406 secs] [Times: user=0.09 sys=0.00, real=0.01 secs]

当CPU过高时,GC日志停留在[GC (Allocation Failure) 2015-10-10T10:18:10.564+0800: 71147.518: [ParNew:,没有其他日志。

当我执行jstack命令时,打印的日志

2015-10-10T10:17:50.757+0800: 53501.137: [GC (Allocation Failure) 2015-10-10T10:17:50.757+0800: 53501.137: [ParNew: 210022K->245K(235968K), 369.6907808 secs] 400188K->1
90410K(1022400K), 369.6909604 secs] [Times: user=3475.15 sys=11.69, real=369.63 secs] 

why GC Threads made the cpu load too high.

您的 JVM 可能是 运行 完整 GC。由于您的 JVM 可能是 运行 一个巨大的堆(由 10.6 GB 的内存大小暗示),这将花费很长时间。也有可能是您的系统正在抖动虚拟内存。

why after i used jstack command the cpu became nomal.

巧合……大概吧。 GC 在您 运行 jstack 时完成。


如果您想对此进行调查,我建议您打开垃圾收集日志记录,并尝试将 CPU 高负载时段与 GC activity.

相关联

GC 日志应该告诉您的另一件事是 Tomcat 的堆是否太满。如果您的 webapps 有内存泄漏,那么这将导致堆填满无法被垃圾回收的对象。随着时间的推移,这将导致 JVM 花费越来越多的时间 运行 GC。如果这是问题所在,那么您需要查找并修复内存泄漏。

只是猜测,您 可能 受到某些内核版本中 futex_wait bug 的影响。

更一般地说,jstack -F 向进程发送一个信号,这将中断任何可能正在休眠的线程。因此,也许 GC 线程只是自旋等待另一个以某种方式错过了唤醒的线程。 IE。如果它确实卡在 GC 中并发送信号解决了问题,那么这可能指向锁定或内存排序错误,如果不在内核中,则在 JVM 中。

您可以尝试向进程发送 SIGBREAK 而不是使用 jstack -F,看看是否有相同的效果。