这时候就需要请出这两位 debug 利器了 ———— pstack & strace
pstack 是 Linux 系统下的一个命令行工具,此命令可以显示指定进程每个线程的堆栈快照,便于排查程序异常和性能评估
pstack 是基于 gdb 实现的,通过 man pstack 可以发现,它其实是 gstack 的一个软链接
而 gstack 则是封装了 gdb 功能的 shell 脚本,通过 " thread apply all bt " 的命令获得输出所有的线程堆栈信息,再用 sed 进行替换和过滤
使用 pstack 获得的进程堆栈是程序的静态信息,而使用 strace 可以获得程序的动态信息,即程序现在正在做什么(执行哪些系统调用和所接收的信号)
strace 的功能主要是通过 ptrace 这个系统调用来实现的,它提供了父进程观察/控制子进程的能力
详见:ptrace(2) - Linux man page
当使用了 pstrace 跟踪子进程后,所有发送给被跟踪子进程的信号都会转发给父进程(SIGKILL 除外),而子进程则会阻塞,被标注为 TASK_TRACED 状态
父进程收到信号后,可以对阻塞的子进程进行检查和修改,然后让子进程继续运行
关于 strace 的参数可以参考:strace 跟踪进程中的系统调用
或者查看 Linux 手册 man strace
通过 ps / pidof 命令获取到异常进程的 pid,执行 pstack [pid],我们可以获得以下输出:

从上面的输出中我们可以得到很多信息
- 当前进程中有多少线程
- 各线程当前的调用堆栈(即这个线程正在做什么)
通过这些信息,我们可以简单判断线程是否挂死或者阻塞,再通过堆栈信息定位到代码中具体的函数进一步排查
另外需要注意一点,只有保留了 debug symbols 的程序才可以 pstack,否则将看不到调用栈(如下图)

strace 的用法也很简单,常用的选项有这几个:
- -f 跟踪目标进程,以及目标进程创建的所有子进程
- -t 在输出中的每一行前加上时间信息(-tt 表示微秒级)
- -T 显示每个系统调用所耗的时间
执行 strace ... -p [pid] 我们将获得如下的输出:

通过观察系统调用我们可以确认当前程序的行为,分析其消耗的时间、返回值是否正常
可以过滤指定的线程号,确认当前线程的行为是否符合预期
如果执行命令后完全没有输出,那么可以怀疑是否由于网络、IO等原因导致阻塞,或程序产生死锁
另外分析 pstack / strace 的信息时,最好和日志对照观察
版权声明:
本文来源网络,所有图片文章版权属于原作者,如有侵权,联系删除。
本文网址:https://www.mushiming.com/mjsbk/14252.html