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

时间:2015-10-10 01:39:52

标签: java garbage-collection jstack

今天,我发现服务器的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命令打印转储信息。例如"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变得正常了!

  6. 以下是我的问题:

    1. 为什么GC Threads使cpu负载过高。
    2. 为什么在我使用jstack命令后,cpu变得正常。
    3. 每次都超过这个时间。

      以下是一些正常日志。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] 
      

2 个答案:

答案 0 :(得分:4)

猜测,可能会受某些内核版本中的futex_wait bug影响。

更一般地说,java.time向进程发送一个信号,该信号将中断任何可能正在休眠的线程。所以也许GC线程只是旋转等待另一个错误唤醒的线程。即如果它确实卡在GC中并且发送信号修复了问题,那么这可能指向锁定或内存排序错误,如果不在内核然后在JVM中。

您可以尝试将jstack -F发送到流程,看看是否有相同的效果,而不是使用jstack -F

答案 1 :(得分:0)

  

为什么GC线程使CPU负载过高。

您的JVM可能正在运行完整的GC。而且由于你的JVM可能运行的是一个巨大的堆(以10.6 GB的内存大小暗示),这需要很长时间。您的系统也可能会破坏虚拟内存。

  

为什么我使用jstack命令后cpu变得正常。

巧合......可能。运行jstack时GC已完成。

如果您想对此进行调查,我建议您打开垃圾收集日志记录,并尝试将高CPU负载的周期与GC活动相关联。

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