C++ CPU程序占用率高问题排查

0. 简介

我们在之前介绍了使用Valgrind、perf、AddressSanitzer等工具来完成内存泄漏的检测,当然内存泄漏以外还有cpu的占用率变高这类问题。作者在这里提供几个方法来对C++程序中CPU程序占用率高问题排查。

1. pstack堆栈查看

pstack 命令可以监听日志,Linux 系统默认没有这个命令。所以我们需要安装pstack

sudo apt install pstack

在ubuntu下使用apt安装时,可能会出现无法使用的问题,解决方法是:直接在/usr/bin下新建一个名为pstack的脚本文件,并给sudo权限

#!/bin/sh
  
if test $# -ne 1; then
    echo "Usage: `basename $0 .sh` <process-id>" 1>&2
    exit 1
fi
 
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"
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
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:-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调用的结果:

按照下面的步骤检查一下线程内部的问题

  1. 命令:top -c。 输入大写P,top的输出会按使用cpu多少排序

    PID就是进程号,我程序的进程号是4918。

  2. 查看耗CPU的线程号

     命令:`top -Hp` 进程号。 同样输入大写`P`,`top`的输出会按使用cpu多少排序。
    
     输入`top -Hp 4918`,展示内容如图:
    

  可以看出PID是4927的线程占到了100%的cpu,我的业务日志是打印线程号的
  1. 查看耗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):实时信号的最大值。

我们在这里可以使用kill -s ABRT命令,这可以向进程发送ABRT信号,该信号会导致进程异常终止并生成核心转储文件。通常情况下,这个信号是用来告诉进程发生了严重的错误,需要进行核心转储以便进行调试和分析。然后操作就是和我们看coredump操作一致了。

或者通过下面指令来完成定位

gdb -nx /proc/pid/exe pid
backtrace

…详情请参照古月居

  • 25
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
C++CPU的原因可能有多种,以下是一些常见的原因: 1. 程序设计问题:可能是程序中存在一些不必要的循环或递归,导致CPU资源被浪费。 2. 算法问题:使用低效的算法或数据结构,导致程序在执行时需要大量的计算资源。 3. 并发问题:如果程序中存在多个线程或进程,并且它们之间没有得到良好的同步或调度,可能会导致CPU占用率。 4. 外部资源依赖:如果程序依赖于外部资源(如网络、数据库等),当这些资源无法及时响应时,CPU可能会持续等待,导致占用率。 5. 编译选项问题:编译时选择了错误的优化选项,导致生成的代码效率低下,从而使CPU占用率增加。 要解决CPU占用率问题,可以通过以下方法进行优化: 1. 优化算法和数据结构:选择更效的算法和数据结构来减少计算量。 2. 优化程序设计:检查程序中是否存在不必要的计算和循环,并进行优化。 3. 合理使用并发:确保多线程或多进程之间的同步和调度良好,避免资源竞争和无效的等待。 4. 优化外部资源访问:合理使用缓存、异步调用等技术,以减少对外部资源的依赖和等待时间。 5. 选择合适的编译选项:根据实际情况选择适合的编译优化选项,以生成效的代码。 请注意,以上只是一些常见的原因和优化方法,具体情况可能因程序和环境而异。如果问题仍然存在,可能需要进行更详细的代码分析和性能调优。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

敢敢のwings

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值