检测最耗cpu的线程的脚本

这个脚本用于定位出当前java进程里最耗cpu的那个线程,给出cpu的占用率和当前堆栈信息。这个脚本仅限于linux上,我没有找到在mac下定位线程使用cpu情况的工具,如果你知道请告诉我一下。

先模拟一个耗cpu的java进程,启动一个scala的repl并在上面跑一段死循环:

scala> while(true) {}

脚本执行效果:

$ ./busythread.sh `pidof java`
tid: 431  cpu: %98.8
"main" prio=10 tid=0x00007f777800a000 nid=0x1af runnable [0x00007f7781c2e000]
    java.lang.Thread.State: RUNNABLE
    at $line3.$read$$iw$$iw$.<init>(<console>:8)
    at $line3.$read$$iw$$iw$.<clinit>(<console>)
    at $line3.$eval$.$print$lzycompute(<console>:7)
    - locked <0x00000000fc201758> (a $line3.$eval$)
    at $line3.$eval$.$print(<console>:6)
    at $line3.$eval.$print(<console>)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at scala.tools.nsc.interpreter.IMain$ReadEvalPrint.call(IMain.scala:739)
    at scala.tools.nsc.interpreter.IMain$Request.loadAndRun(IMain.scala:986)
    at scala.tools.nsc.interpreter.IMain$WrappedRequest$$anonfun$loadAndRunReq$1.apply(IMain.scala:593)
    at scala.tools.nsc.interpreter.IMain$WrappedRequest$$anonfun$loadAndRunReq$1.apply(IMain.scala:592)
    at scala.reflect.internal.util.ScalaClassLoader$class.asContext(ScalaClassLoader.scala:31)
    at scala.reflect.internal.util.AbstractFileClassLoader.asContext(AbstractFileClassLoader.scala:19)
    at scala.tools.nsc.interpreter.IMain$WrappedRequest.loadAndRunReq(IMain.scala:592)
    at scala.tools.nsc.interpreter.IMain.interpret(IMain.scala:524)
    at scala.tools.nsc.interpreter.IMain.interpret(IMain.scala:520)

脚本内容:

#!/bin/bash

if [ $# -eq 0 ];then
    echo "please enter java pid"
    exit -1
fi

pid=$1
jstack_cmd=""

if [[ $JAVA_HOME != "" ]]; then
    jstack_cmd="$JAVA_HOME/bin/jstack"
else
    r=`which jstack 2>/dev/null`
    if [[ $r != "" ]]; then
        jstack_cmd=$r
    else
        echo "can not find jstack"
        exit -2
    fi
fi

#line=`top -H  -o %CPU -b -n 1  -p $pid | sed '1,/^$/d' | grep -v $pid | awk 'NR==2'`

line=`top -H -b -n 1 -p $pid | sed '1,/^$/d' | sed '1d;/^$/d' | grep -v $pid | sort -nrk9 | head -1`
echo "$line" | awk '{print "tid: "$1," cpu: %"$9}'
tid_0x=`printf "%0x" $(echo "$line" | awk '{print $1}')`
$jstack_cmd $pid | grep $tid_0x -A20 | sed -n '1,/^$/p'

脚本已放到服务器上,可以通过下面的方式执行:

$ bash <(curl -s http://hongjiang.info/busythread.sh)  java_pid

update: 感谢容若的反馈,很多环境的procps版本较低,top还不支持-o参数,排序那块用sort解决了,脚本已更新。

检测最耗cpu的线程的脚本》上有3条评论

  1. 李鼎

    之前也整理了,经过4年改进,现在功能丰富和完善程度很高了,可以看看试试,哈哈

    https://github.com/oldratlee/useful-scripts/blob/master/docs/java.md#beer-show-busy-java-threadssh

    用于快速排查Java的CPU性能问题(top us值过高),自动查出运行的Java进程中消耗CPU多的线程,并打印出其线程栈,从而确定导致性能问题的方法调用。

    用法

    show-busy-java-threads.sh
    # 从 所有的 Java进程中找出最消耗CPU的线程(缺省5个),打印出其线程栈。

    show-busy-java-threads.sh -c

    show-busy-java-threads.sh -c -p
    # -F选项:执行jstack命令时加上-F选项(强制jstack),一般情况不需要使用
    show-busy-java-threads.sh -p -F

    show-busy-java-threads.sh -s
    # 对于sudo方式的运行,JAVA_HOME环境变量不能传递给root,
    # 而root用户往往没有配置JAVA_HOME且不方便配置,
    # 显式指定jstack命令的路径就反而显得更方便了

    show-busy-java-threads.sh -a
    # 记录到文件以方便回溯查看

    show-busy-java-threads.sh []
    # 多次执行;这2个参数的使用方式类似vmstat命令

    ##############################
    # 注意:
    ##############################
    # 如果Java进程的用户 与 执行脚本的当前用户 不同,则jstack不了这个Java进程。
    # 为了能切换到Java进程的用户,需要加sudo来执行,即可以解决:
    sudo show-busy-java-threads.sh

    # 帮助信息
    $ show-busy-java-threads.sh -h
    Usage: show-busy-java-threads.sh [OPTION]… [delay [count]]
    Find out the highest cpu consumed threads of java, and print the stack of these threads.

    Example:
    show-busy-java-threads.sh # show busy java threads info
    show-busy-java-threads.sh 1 # update every 1 seconds, (stop by eg: CTRL+C)
    show-busy-java-threads.sh 3 10 # update every 3 seconds, update 10 times

    Options:
    -p, –pid find out the highest cpu consumed threads from the specifed java process,
    default from all java process.
    -c, –count set the thread count to show, default is 5
    -a, –append-file specify the file to append output as log
    -s, –jstack-path specify the path of jstack command
    -F, –force set jstack to force a thread dump(use jstack -F option)
    -h, –help display this help and exit
    delay the delay between updates in seconds
    count the number of updates
    delay/count arguments imitates style of vmstat command

    回复

发表评论

电子邮件地址不会被公开。 必填项已用*标注