在分析CPU佔用率很高的線程以及問題定位時,一般都是使用top和jstack命令,但是整個過程比較慢,確實使用arthas就可以非常快速地定位到耗時最快的線程
使用arthas
https://arthas.aliyun.com/doc/quick-start.html
curl -O https://arthas.aliyun.com/arthas-boot.jar
java -jar arthas-boot.jar
定位CPU佔用率最高的線程
- 按照CPU使用率排序,並展示前n個線程
thread -n {number}
[arthas@1]$ thread -n 1
"arthas-command-execute" Id=8286 cpuUsage=0.4% deltaTime=0ms time=22ms RUNNABLE
at sun.management.ThreadImpl.dumpThreads0(Native Method)
at sun.management.ThreadImpl.getThreadInfo(ThreadImpl.java:448)
at com.taobao.arthas.core.command.monitor200.ThreadCommand.processTopBusyThreads(ThreadCommand.java:206)
at com.taobao.arthas.core.command.monitor200.ThreadCommand.process(ThreadCommand.java:122)
at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl.process(AnnotatedCommandImpl.java:82)
at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl.access$100(AnnotatedCommandImpl.java:18)
at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl$ProcessHandler.handle(AnnotatedCommandImpl.java:111)
at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl$ProcessHandler.handle(AnnotatedCommandImpl.java:108)
at com.taobao.arthas.core.shell.system.impl.ProcessImpl$CommandProcessTask.run(ProcessImpl.java:385)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
- 展示指定線程的線程棧
thread [pid]
[arthas@1]$ thread 3422
"grpc-default-executor-2" Id=3422 TIMED_WAITING on java.util.concurrent.SynchronousQueue$TransferStack@56b72395
at sun.misc.Unsafe.park(Native Method)
- waiting on java.util.concurrent.SynchronousQueue$TransferStack@56b72395
at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)
at java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(SynchronousQueue.java:460)
at java.util.concurrent.SynchronousQueue$TransferStack.transfer(SynchronousQueue.java:362)
at java.util.concurrent.SynchronousQueue.poll(SynchronousQueue.java:941)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1073)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
爲什麼有時候CPU使用率排第一的線程狀態是WAITING?
在定位問題的時候,發現CPU使用率最高的線程的狀態是WAITING,一個在等待的線程怎麼可能佔用CPU呢? 實際上這是因爲CPU使用率的計算是通過採樣的方式得到的,並不是當前時刻的CPU使用率,所以原因是在進入WAITING之前,佔用了很多的CPU