在Linux下如果发现程序运行异常,比如CPU、内存占用很高,可以采用Linux下自带的一些命令,帮助我们找到问题所在。
1. top+pstack+gdb的组合拳
闲言少说,先直接上操作实例,再做原理讲解。
1.1 用top命令找到最占CPU的进程
# top
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
22688 root 20 0 1842m 136m 13m S 110.0 0.9 1568:44 test-program
1.2 使用pstack跟踪进程栈
pstack是一个shell脚本,用于打印正在运行的进程的栈跟踪信息,它实际上是gstack的一个链接,而gstack本身是基于gdb封装的shell脚本。此命令可显示每个进程的栈跟踪。
pstack
命令必须由相应进程的属主或者root运行,我们可以使用pstack来确定进程挂起的位置。此命令允许使用的唯一选项就是要检查的进程的PID。与jstack
相比,它能对潜在的死锁予以提示,而pstack只提供了线索,需要gdb进一步的确定。
pstack是gdb的一部分,如果系统没有pstack命令,使用yum搜索安装gdb即可。
这个命令在排查进程问题时非常有用,比如我们发现一个服务一直处于work状态(如假死状态,好似死循环),使用这个命令就能轻松定位为题所在。我们可以在一段时间内,多次执行pstack,若发现代码栈总是停在同一个位置,那个位置就需要重点关注,和可能就是出问题的地方。
然后使用top命令查看指定进程最耗CPU的线程:
# top -H -p 22688
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
22970 root 20 0 1842m 136m 13m R 100.2 0.9 1423:40 test-program
从上面我们看到,找到的最耗CPU的线程为22970
。
注: 这里的PID是系统给每个线程分配的唯一的线程号,不是进程号,但名称也是PID。这两者的具体区别可见linux中pid,tid, 以及 真实pid的关系
接着我们使用线程号PID反查该线程在进程中的内部ID标识:
# pstack 22688 | grep 22970
Thread 10 (Thread 0x7fa92f5fe700 (LWP 22970)):
从上面我们就找到了线程22970对应的是线程10。
之后,我们使用vim
查看进程快照,定位到具体的线程,并查看其调用堆栈:
上面的操作基本定位到了具体线程和大概的函数。如果想查看具体的原因,如现场的函数中变量的数值等,就要使用GDB的实时调试功能。
1.3 使用GDB实时调试进程
[参看]:
-
Linux下top+pstack+gdb的组合拳定位程序进程线程问题并调试
-
gdb如何确定内存 已经释放
-
LD_PRELOAD作用
-
LD_PRELOAD基础用法