如何排查C++程序的CPU占用过高的问题

文章目录

可能的原因

程序设计的BUG

  • 有死循环
  • 低效算法与数据结构
  • 滥用自旋锁
  • 频繁的系统调用,导致用户态与内核态频繁切换

系统资源问题

  • 内存不足,系统频繁使用硬盘交换分页

恶意软件

  • 后台运行的病毒或流氓软件或自动更新的软件

硬件问题

  • 散热不良
  • 硬件老化

通常步骤

  1. 找到问题的进程
  2. 找到问题的线程
  3. 找到问题的代码位置
  4. 分析原因

一个简单的问题代码

cpp 复制代码
#include <iostream>
#include <thread>
#include <vector>

void busy_task() 
{
    while(true) {}
}

void slow_algorithm() 
{
    for (auto i = 0L ; i < 1000000000L; ++i)
    {
        volatile auto x = i * i;
    }
}

int main()
{
    std::vector<std::thread> threads;
    threads.emplace_back(busy_task);
    threads.emplace_back(slow_algorithm);
    for(auto& t: threads)
    {
        t.join();
    }
    return EXIT_SUCCESS;
}

程序以DEBUG模式编译成fst0.exe 与 fst0.pdb

在windows平台上如何排查

Windows Process Explorer

需要借助工具WindowsProcessExplorer

fst0.exe 在运行中

以管理员权限运行ProcExp,切记32 位的fst0.exe 要用32位的ProcExp,64位的fst0.exe要用64位的ProcExp

过滤出目标同时打开线程窗口

可以看到占用CPU过高的线程

我们需要设置符号文件路径


32位的程序用32位的pdb符号文件路径,64位的程序用64位的pdb符号文件路径

然后右键点击线程中的调用堆栈

可以清晰的看到程序是卡在busy_task那个函数上了!

WinDBG

怎么安装WinDbg这里就跨过,使用WinDbg时要切记,32位的程序使用32位的WinDbg调试,同时要使用32位pdb文件,64位的程序使用64位的WinDbg调试,同时要使用64位的pdb文件WinDbg最好用管理员权限打开

先行设置好符号路径与源码路径



现在Fst0.exe 已经在运行当中了,使用WinDbg来附加到进程,


看到这里WinDbg执行 int 3 软中断暂停了进程。

在Command里面执行!runaway看看各个线程的执行时间,可以看到4号线程执行时间最长

可以看看4号线程的调用堆栈

可以明显看到卡在了busy_task 函数,点击后面的蓝色链接可以看到源码

在Command里面使用qd命令退出调试

更多关于WinDBG的知识请上网自行搜索学习

在Linux平台如何排查

使用TOP + GDB

先以Debug模式编译出fst0

shell 复制代码
g++ -g fst0.cc -o fst0 -lpthread

然后运行 fst0

然后使用top

可以看到fst0的cpu占用很高

现在知道fst0的进程号是2473,还需要知道fst0的耗时线程是哪个

执行

shell 复制代码
top -H -p 2473

可以得到线程信息

可以看到有两个线程,2473主线程号与进程号相同,2474是耗时的那个子线程号

现在需要把2474那个线程的堆栈信息打印出来

shell 复制代码
sudo gdb -p 2474 -ex "thread apply all bt" -ex "detach" -ex "quit" > stack.log
cat stack.log

可以清楚看到程序是卡在busy_task函数,fst0.cc 文件的第8行那里。

更多gdb 相关知识自行上网学习。

Perf

perf 是Linux内核提供的性能分析工具。若你需要此工具,安装步骤如下:

shell 复制代码
# 更新软件包列表
sudo apt update

# 安装与当前内核匹配的linux-tools
sudo apt install linux-tools-$(uname -r)

# 验证安装
perf --version

编译程序,运行程序,打到程序PID与上面方法相同

使用perf实时查看进程热点,动态显示系统中消耗 CPU 最多的函数或进程

shell 复制代码
# 全局监控所有进程的热点
sudo perf top

# 仅监控指定 PID 的进程
sudo perf top -p <PID>

例子

清晰的看到耗时函数是哪个

相关推荐
zh_xuan4 分钟前
c++ std::pair
开发语言·c++
CodeWithMe26 分钟前
【C/C++】EBO空基类优化介绍
开发语言·c++
k要开心1 小时前
从C到C++语法过度1
开发语言·c++
whoarethenext1 小时前
使用 C/C++的OpenCV 实时播放火柴人爱心舞蹈动画
c语言·c++·opencv
能工智人小辰1 小时前
Codeforces Round 509 (Div. 2) C. Coffee Break
c语言·c++·算法
梦星辰.1 小时前
VSCode CUDA C++进行Linux远程开发
linux·c++·vscode
whoarethenext2 小时前
C++ OpenCV 学习路线图
c++·opencv·学习
闻缺陷则喜何志丹2 小时前
【强连通分量 缩点 拓扑排序】P3387 【模板】缩点|普及+
c++·算法·拓扑排序·洛谷·强连通分量·缩点
hutaotaotao3 小时前
c++中的输入输出流(标准IO,文件IO,字符串IO)
c++·io·fstream·sstream·iostream
AL流云。3 小时前
【优选算法】C++滑动窗口
数据结构·c++·算法