0. 简介
我们在之前介绍了使用Valgrind、perf、AddressSanitzer等工具来完成内存泄漏的检测,当然内存泄漏以外还有cpu的占用率变高这类问题。作者在这里提供几个方法来对C++程序中CPU程序占用率高问题排查。
1. pstack堆栈查看
pstack 命令可以监听日志,Linux 系统默认没有这个命令。所以我们需要安装pstack
sudo apt install pstack
在ubuntu下使用apt安装时,可能会出现无法使用的问题,解决方法是:直接在/usr/bin下新建一个名为pstack的脚本文件,并给sudo权限
#!/bin/shif test $# -ne 1; thenecho "Usage: `basename $0 .sh` <process-id>" 1>&2exit 1
fiif test ! -r /proc/$1; thenecho "Process $1 not found." 1>&2exit 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"
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 ; thenbacktrace="thread apply all bt"fi
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 ; thenbacktrace="thread apply all bt"fi
fiGDB=${GDB:-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'
启动:
sudo bash /usr/bin/pstack 27596
然后确保pstack命令被以root权限或者适当的权限运行,并确保目标进程处于可调试状态,可以通过使用gdb或者其他调试工具来设置进程的调试。pstack显示的其实是进程在某一刻的调用栈。
以htop为例,这是我们用pstack调用的结果:
这个是用gdb调用的结果:
按照下面的步骤检查一下线程内部的问题
-
命令:
top -c
。 输入大写P,top的输出会按使用cpu多少排序PID就是进程号,我程序的进程号是4918。
-
查看耗CPU的线程号
命令:`top -Hp` 进程号。 同样输入大写`P`,`top`的输出会按使用cpu多少排序。输入`top -Hp 4918`,展示内容如图:
可以看出PID是4927的线程占到了100%的cpu,我的业务日志是打印线程号的
-
查看耗CPU的任务
上面找到了耗CPU的线程,那这个线程在做什么呢?
看线程在干什么,可以看线程的堆栈,命令是pstack 进程号,会输出所有线程的堆栈信息。
输入
pstack 4918
,并搜索线程4927的堆栈,展示内容如图:
2. 使用kill功能完成堆栈抓取
除了ptsack以外,还可以使用kill完成高CPU占用时候的数据抓取,相信大家基本使用的是kill -9 + 进程号的方法杀程序。但是我们可以使用kill -s的方法完成更多的功能:
这里是一些常见的kill信号和它们的含义:
- HUP (1):挂起信号,通常用于通知进程重新加载配置文件。
- INT (2):中断信号,通常由用户按下Ctrl+C来发送,用于中断进程。
- QUIT (3):退出信号,通常由用户按下Ctrl+\来发送,用于请求进程退出并生成核心转储文件。
- ILL (4):非法指令信号,表示进程执行了非法指令。
- TRAP (5):陷阱信号,通常用于调试目的。
- ABRT (6):中止信号,通常用于请求进程异常终止并生成核心转储文件。
- BUS (7):总线错误信号,表示进程执行了非法内存访问。
- FPE (8):浮点异常信号,表示进程执行了非法的浮点运算。
- KILL (9):强制终止信号,用于立即终止进程,进程无法捕获或忽略这个信号。
- USR1 (10):用户自定义信号1,可以由用户自定义处理。
- USR2 (12):用户自定义信号2,可以由用户自定义处理。
- PIPE (13):管道破裂信号,表示进程尝试写入已被关闭的管道。
- ALRM (14):闹钟信号,用于定时器通知。
- TERM (15):终止信号,通常用于请求进程正常终止。
- CONT (18):继续信号,用于恢复已停止的进程。
- STOP (19):停止信号,用于暂停进程的执行。
- TSTP (20):终端停止信号,通常由用户按下Ctrl+Z来发送,用于请求进程暂停。
- TTIN (21):后台进程尝试读取终端信号。
- TTOU (22):后台进程尝试写入终端信号。
- URG (23):紧急条件信号。
- XCPU (24):CPU时间限制信号。
- XFSZ (25):文件大小限制信号。
- VTALRM (26):虚拟定时器信号。
- PROF (27):性能计数器定时器信号。
- WINCH (28):窗口大小改变信号。
- POLL (29):轮询文件描述符事件信号。
- PWR (30):电源故障信号。
- SYS (31):保留供系统使用的信号。
- RTMIN (34):实时信号的最小值。
- RTMAX (64):实时信号的最大值。
## …详情请参照[古月居](https://www.guyuehome.com/45663)
3. htop完成堆栈追踪
htop非linux系统的自带工具,需要用户自行安装
sudo apt install htop
htop的界面与top很类似,但功能更强,一大特色是支持鼠标和滚轮操作:
\
此外还可以切换到大写,并使用P来完成CPU利用率排序,使用F完成该进程在界面中高亮显示
使用sudo运行htop,还可以输入s完成strace命令追踪进程的系统调用情况
其他常用指令
- / 或 F3 : 搜索一个进程
- \ 或 F4 : 模糊搜索,过滤器
- F5 :树状显示
- F7 :减小nice,增加优先级
- F8 :增大nice,减少优先级
- F9 :杀死进程
4. 使用strace完成堆栈动态追踪
首先也是安装strace
sudo apt-get install strace
strace是一个用来动态追踪进程处理的的系统调用和信号的命令。输入下面指令就可以获取信息
sudo strace -p 29844
高级操作可以参考这篇文章:https://cloud.tencent.com/developer/article/1667055
5. 参考连接
https://blog.csdn.net/lmb1612977696/article/details/89404019
https://cloud.tencent.com/developer/article/1667055
http://www.wangkaixuan.tech/?p=943