pstack
pstack:查看进程调用栈
使用:pstack 进程号
原理:查看pstack命令,可以看到pstack是gstack的软链接。(注意:笔者是使用的centos,ubuntu等可能有区别)
gstack:又是一个脚本。两者都位于usr/bin/下
1 [xxxxx]#ls /usr/bin/pstack -la
2 lrwxrwxrwx. 1 root root 6 Jul 9 12:04 /usr/bin/pstack -> gstack
gstack源码读者可在如usr/bin/下找到
[root@localhost ~]# cat /usr/bin/gstack #!/bin/sh #判断入参个数是否大于1 if test $# -ne 1; then echo "Usage: `basename $0 .sh` <process-id>" 1>&2 exit 1 fi #判断/proc/下,入参的进程PID是否存在 if test ! -r /proc/$1; then echo "Process $1 not found." 1>&2 exit 1 fi # GDB doesn't allow "thread apply all bt" when the process isn't # threaded; need to peek at the process to determine if that or the # simpler "bt" should be used. backtrace="bt" #新版本kernel,通过判断/proc/ /task/下数量判断是否为多线程 if test -d /proc/$1/task ; then # Newer kernel; has a task/ directory. if test `/bin/ls /proc/$1/task | /usr/bin/wc -l` -gt 1 2>/dev/null ; then backtrace="thread apply all bt" fi #旧版本kernel,通过判断/proc/ /maps下libpthread 数量判断是否为多线程 elif test -f /proc/$1/maps ; then # Older kernel; go by it loading libpthread. if /bin/grep -e libpthread /proc/$1/maps > /dev/null 2>&1 ; then backtrace="thread apply all bt" fi fi GDB=${GDB:-/usr/bin/gdb} # Run GDB, strip out unwanted noise. # --readnever is no longer used since .gdb_index is now in use. $GDB --quiet -nx $GDBARGS /proc/$1/exe $1 <<EOF 2>&1 | set width 0 set height 0 set pagination no $backtrace EOF /bin/sed -n \ -e 's/^\((gdb) \)*//' \ -e '/^#/p' \ -e '/^Thread/p'
脚本意思如下
(1)开始拦截命令携带参数个数
(2)查看进程是否存在 ,在/proc/下查看进程号
(3)注释描述需要判断什么情况时有thread apply all bt 还是bt命令。进程中存在多线程时时有thread apply all bt,进程只有一个线程时使用bt
(4)如果是新版本内核,则使用/proc/PID/task 判断是否为多线程,如果为老版本内核则使用 /proc/PID/maps。判断进程是否为多线程,/proc/PID/task/ 下是否只有一个文件(线程号) 。 ls /proc/PID/task | wc -l 查看线程个数,后者对于新版本内核其实不准确,因为单线程中一样能存在libpthread(编译的时候人为链接libpthread,已实验证实确实不准确)
(5)启动gdb 执行(3)处选择的命令打印堆栈。