当前位置:   article > 正文

如何排查java应用的高CPU占用的问题_java cpu过高排查

java cpu过高排查

这类问题,如果应用不是在容器中运行的(K8S,docker),那排查起来相对简单,无非就是先用top定位哪个java服务的进程的CPU占用较高,再用**top -Hp {pid}**命令来查看具体哪些线程的CPU占用较高,最后通过jstack命令打印服务的线程堆栈信息,再将占用过高的线程的PID转换成16进制到线程堆栈文件中去搜索,找到对应的高CPU占用的线程就行了。

但如果应用是通过容器启动的,那以上路线就行不通了。原因主要是容器内打印出的线程堆栈信息中的线程ID(NID)和通过宿主机本地top -Hp {pid}命令打印出来的线程ID并不一致,这样就无法准确定位到高CPU占用的线程了。那么如何排查容器内应用的高CPU占用的线程呢?最近看到某篇文章中提到的一种方式倒是让我受到一些启发。

我们知道一个线程的状态一共有六种:NEW,RUNNABLE,BLOCKED,WAITING,TIMED_WAITING,TERMINATED. 但其中只有处于RUNNABLE的线程才会占用CPU资源,这个很好理解,只有运行中的线程才会占用资源。但现实当中,并非所有处于RUNNABLE状态的线程都会占用实际的资源,举个简单的例子:

"qtp1786040872-10651" #10651 prio=5 os_prio=0 tid= nid=0x299d runnable [0x00007f9565d04000]
   java.lang.Thread.State: RUNNABLE
	at sun.nio.ch.EPollArrayWrapper.epollWait(Native Method)
	at sun.nio.ch.EPollArrayWrapper.poll(EPollArrayWrapper.java:269)
	at sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:93)
	at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:86)
	- locked <0x00000000edf64238> (a sun.nio.ch.Util$3)
	- locked <0x00000000edf64248> (a java.util.Collections$UnmodifiableSet)
	- locked <0x00000000edf641f0> (a sun.nio.ch.EPollSelectorImpl)
	at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:97)
	at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:101)
	at org.eclipse.jetty.io.ManagedSelector.nioSelect(ManagedSelector.java:149)
	at org.eclipse.jetty.io.ManagedSelector.select(ManagedSelector.java:156)
	at org.eclipse.jetty.io.ManagedSelector$SelectorProducer.select(ManagedSelector.java:572)
	at org.eclipse.jetty.io.ManagedSelector$SelectorProducer.produce(ManagedSelector.java:509)
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.produceTask(EatWhatYouKill.java:360)
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:184)
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:171)
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:129)
	at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:375)
	at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:806)
	at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:938)
	at java.lang.Thread.run(Thread.java:748)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

这个线程虽然处于RUNNABLE状态,但明显在等待网络IO,其实并没有占用什么CPU资源。从这个思路出发,我们很容易就能找出那些其实处于伪RUNNABLE状态的线程,并把它们从问题排查的列表中删除掉,那么剩下的线程,很有可能就是你在寻找的高资源占用的线程了。

人工这样一个一个线程的排查,在线程数量比较多的时候还是有点费事的,这里推荐一个网站,可以快速自动的识别出类似这样真正的高消耗的线程:https://fastthread.io/ 上文所述的理论也是原止于此,原文链接如下:THREAD DUMP ANALYSIS PATTERN – ATHLETE

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/206952?site
推荐阅读
相关标签
  

闽ICP备14008679号