[原]调试实战——程序CPU占用率飙升,你知道如何快速定位吗?

原调试debugwindbghangprocess explorer

前言

如果我们自己的程序的CPU UsageCPU占用率)飙升,并且居高不下,很有可能陷入了死循环。你知道怎么快速定位并解决吗?今天跟大家分享几种定位方法,希望对你有所帮助。

如何判断是否有死循环?

  • 通过电脑风扇的声音猜测。

    如果风扇一直响个不停,说明电脑很热。高CPU占用率会导致CPU发热量增大,从而导致风扇狂响。如果听到风扇响个不停,可以打开任务管理器看看CPU占用率是不是很高。如果发现是我们的进程导致的高CPU占用率,那么可以进一步查看是不是有死循环。

  • 通过CPU占用率来判断。

    对于多核CPU(尤其是性能强劲的CPU),一个核心的满负荷运转,并不会立刻导致CPU发热量明显增大,风扇可能不会有明显响动。这时根据风扇声音不能轻易判断出是否有死循环,但是我们可以通过CPU占用率来判断。

    如果CPU是单核的,那么当CPU处于满负荷运转状态,CPU占用率会接近100%。如果CPU4核的,并且这4个核心都处于满负荷运转状态,那么CPU占用率会接近100%,如果只有一个核心是满负荷运转状态,那么CPU占用率会在25%100 / 4 = 25)左右。如果我们发现某个进程的CPU占用率居高不下,有可能是死循环了。

    {% note info %}
    注意: 很多死循环都是busy类型的,如果是idle类型的死循环,上面的方法不适用。
    {% endnote %}

下面介绍几个我经常使用的工具,可以比较便捷的排查此类的问题。

1. process explorer

在前面的文章里跟大家介绍过,使用process explorer可以查看线程的调用栈CPU占用率。如果程序里的某个功能迟迟不能完成,我的第一反应是,按Ctrl + Shift + Esc打开任务管理器(我已经使用process explorer替换了系统自带的任务管理器,所以启动的是process explorer。如何使用process explorer替换系统自带的任务管理器,请参考文章排错实战——使用process explorer替换任务管理器)。

启动process explorer后,双击我们关心的进程,切换到Thread页,在这里我们可以看到当前进程中的所有线程。双击某个线程就可以查看调用栈,在弹出的调用栈界面,点击左下角的Refresh按钮可以刷新。

如果每次刷新都能看到某个函数,很有可能是在这个函数中出现了死循环。对照源码,也许能直接能看出原因。

{% note info %}

注意: 需要正确加载调试符号才可以看到对应的函数名。

{% endnote %}

2. windbg

如果不能使用process explorer定位到具体的原因,可以使用windbg附加到进程中进行更深入的调查。我们需要找出哪个线程运行的时间最长,因为一般死循环的线程占用的CPU时间会比较长。应该怎么找呢???

  • 使用.ttime命令

    .ttime可以查看当前线程的运行时间(用户态运行时间和内核态运行时间)。但是.ttime有个不足之处——没有输出相关的线程标识。我们需要根据其它信息来获取当前线程的标识。

    如果想查看所有线程的运行时间怎么办呢?当然可以手动切换到另外一个线程,然后执行.ttime。如果线程数量很多的话,这可是个体力活。不要怕,我们可以通过命令~*e .ttime来获取每个线程的运行时间。因为.ttime输出结果中没有线程标识,我们需要执行命令 ~*e ? $tid;.ttime 把对应的线程ID一起输出。

    简单向大家解释下这条命令:

    • ~*e会遍历所有线程并执行后面跟着的命令。其实,~*就可以遍历所有线程,比如我们在前面的文章里用到的~* kvn命令来查看所有线程的调用栈。但是对于某些命令,如果不加ewindbg可能不能正确解析,会报错。
    • ? $tid评估表达式$tid的值,?windbg中表示Evaluate的意思,会评估后面表达式的值。$tid是伪变量,代表了当前线程的线程ID
    • ; 分号是命令分割符。
    • .ttime查看当前线程的运行时间。

    整条命令的效果是:遍历每个线程,输出其对应的线程ID和运行时间。

  • 如果觉得上面的命令太长了,还可以使用更简单的命令!runaway查看线程运行时间。

下面是我用!runaway命令排查高CPU占用率的屏幕录像。

3. visual studio

如果是正在开发的程序在运行过程中出现了死循环,我会考虑用vs来附加到进程(如果进程是通过Ctrl + F5启动的话,并没有被调试)。然后通过Parallel Stacks查看所有线程,并用肉眼查找可能出问题的线程。因为我不知道vs中是否有类似!runaway的命令。如果哪位小伙伴有更好的办法,请一定要留言告诉我!

{% note info %}

小提示:CTRL + ALT + P可以快速打开附加进程界面。

{% endnote %}

小结

以上三种工具,我会先使用process explorer大体定位下问题,因为可以非常方便的通过Ctrl + Shift + Esc启动。如果用process explorer解决不了,我会根据情况使用windbg或者vs。如果vs正开着(通常是正在写代码的时候),就顺手用vs附加到对应的进程上。如果vs没开着,当然会使用windbg进行排查了。??

实战代码

如果你想动手实战,复制下面的代码到工程里就可以实战了。

简单介绍下代码:

  • 示例代码中启动了8个线程,是为了增大排查的难度,只有一个线程的情况太简单了。
  • 函数FindFirstRepeatElementIndex()的用途是找到给定的数据中第一次出现重复的数据的索引。
  • 除了我们发现的死循环的问题,还有什么地方可以优化呢?命名,效率,各个方面都可以优化哦,欢迎留言交流。
#include <vector>
#include <future>
#include <iostream>

int FindFirstRepeatElementIndex(bool bExcute)
{
  if (!bExcute)
  {
    return -1;
  }

  int idx = -1;
  std::vector<int> datas = { 1 , 3, 5, 7, 9, 11, 11, 13, 14, 15, 16, 17 };
  for (size_t i = 0; i < datas.size(); ++i)
  {
    for (size_t j = i = 1; j < datas.size(); ++j)
    {
      if (datas[j] == datas[i])
      {
        idx = i;
        break;
      }
    }
  }

  return idx;
}

#define THREAD_COUNT 8
int main()
{
  std::future<int> results[THREAD_COUNT];

  int realExcuteIdx = rand() % THREAD_COUNT;
  for (int idx = 0; idx < THREAD_COUNT; ++idx)
  {
    bool bRealExcute = (realExcuteIdx == idx);
    results[idx] = std::async(FindFirstRepeatElementIndex, bRealExcute);
  }

  for (auto& one_result : results)
  {
    std::cout<< one_result.get() << std::endl;
  }

  return 0;
}

总结

  • 使用process explorer的线程相关功能,在某些情况下,我们甚至可以不用调试器,对照源码就可以找出问题所在。
  • visual studio的并行调用栈可以让我们一次性看到所有线程的调用栈,很是方便。不像Call Stack,每次只能查看一个线程的调用栈。
  • 一般,如果一个线程的运行时间远大于其它线程,这个线程很有可能是与死循环相关的线程。
  • windbg!runaway命令可以查看每个线程运行的时间,运行时间最长的线程会排在第一位。
  • ~*e ? $tid;.ttime可以查看所有线程的运行时间。
  • ‘~Ns‘ 切换到第N号线程。
  • ~~[TID]s 切换到TID对应的线程。

参考资料

  • 《格蠹汇编》
  • 《Windows Sysinternals 实战指南》

原文地址:https://www.cnblogs.com/bianchengnan/p/12242392.html

时间: 2024-08-28 18:25:29

[原]调试实战——程序CPU占用率飙升,你知道如何快速定位吗?的相关文章

实战开发经验: 如何降低CPU占用率

在软件开发和性能测试中,CPU占用率是一个很重要的指标,到底有哪些因素会导致CPU占用率上升呢?又有哪些手段可以降低CPU的占用率呢?本文是"Jhuster的专栏"的<实战开发经验 >系列又一篇文章,简单地总结了一下关于CPU占用率的那些事. 1. 如何测试CPU占用率? 首先,我们要学会如何测试程序的CPU占用率,这里简单地给出最基础的方法: Windows上可以通过Ctrl+Alt+Del组合调出"任务管理器",然后查看指定进程的详细信息即可. Li

线上Java程序导致服务器CPU占用率过高的问题排除过程

博文转至:http://www.jianshu.com/p/3667157d63bb,博文更好效果看原版,转本博文的目的就算是个书签吧,需要时候可以定位原文学习 1.故障现象 客服同事反馈平台系统运行缓慢,网页卡顿严重,多次重启系统后问题依然存在,使用top命令查看服务器情况,发现CPU占用率过高. 2.CPU占用过高问题定位 2.1.定位问题进程 使用top命令查看资源占用情况,发现pid为14063的进程占用了大量的CPU资源,CPU占用率高达776.1%,内存占用率也达到了29.8% [[

C#程序,如何有效减少CPU占用率

最近开发的项目中,由于会用到比较耗费CPU资源的第三方程序ffmpeg来处理视频.所以在网上找了一下,如何解决这种问题. 于是乎,就得到一个结论,减少CPU占用率,可以通过减少使用的CPU数量,在Window系统下,打开一个exe程序,系统会默认使用所有CPU作为处理. 是不是减少CPU使用数量,就可以减少CPU占用率呢,答案是肯定的. 参考代码:这里使用calc作为例子. Process p = new Process(); p.StartInfo.FileName = @"c:\window

记一次线上Java程序导致服务器CPU占用率过高的问题排除过程

https://blog.csdn.net/u013991521/article/details/52781423 1.故障现象 客服同事反馈平台系统运行缓慢,网页卡顿严重,多次重启系统后问题依然存在,使用top命令查看服务器情况,发现CPU占用率过高. 2.CPU占用过高问题定位 2.1.定位问题进程 使用top命令查看资源占用情况,发现pid为14063的进程占用了大量的CPU资源,CPU占用率高达776.1%,内存占用率也达到了29.8% [ylp@ylp-web-01 ~]$ top t

《编程之美》学习笔记——指挥CPU占用率

问题: 写一个程序,让用户来决定Windows任务管理器(Task Manager)的CPU占用率(单核).有以下几种情况: 1.CPU占用率固定在50%,为一条直线 2.CPU的占用率为一条直线,具体占用率由命令行参数决定(范围1~100) 3.CPU的占用率状态为一条正弦曲线 4.多核处理器情况下上述问题怎么解决 分析与解答 首先确定CPU占用率的定义,即在任务管理器的一个刷新周期内,CPU忙(执行应用程序)的时间和刷新周期总时间的比率,就是CPU的占用率,也可以说成,任务管理器中显示的是每

linux上限制用户进程数、cpu占用率、内存使用率

限制进程CPU占用率的问题,给出了一个shell脚本代码如下: renice +10 `ps aux | awk '{ if ($3 > 0.8 && id -u $1 > 500) print $2}'` 其中用到ps获取进程信息,其实 ps中%CPU一列的意义是进程实际占有CPU时间和它存活时间的比值,这个值能反应进程对CPU的消耗,但不能准确反应进程所占CPU时间占整个系统CPU的百分比. 而top输出中的%CPU这一列正是进程所占CPU时间占整个系统CPU的百分比,用于

浅析 Pycharm 内存、cpu 占用率

浅析 Pycharm  内存.cpu 占用率 本机配置参数: ------------------------------------------ Windows 10 专业版   X64 ------------------------------------------- SSD : 250+G  2.40GHz ------------------------------------------- 内存:8G ----------------------------------------

[转帖]Java性能检测工具-记录一次通过jstack排查Linux服务器CPU占用率很高的实践

Java性能检测工具-记录一次通过jstack排查Linux服务器CPU占用率很高的实践 https://www.jianshu.com/p/d4e31301ba2e 一.问题描述 Linux服务器的配置是4核16G,将war包部署到tomcat后,启动tomcat,发现内存占用率不高,但是CPU一直高达100%:浏览器输入相关url也无法访问该项目,且tomcat的进程一直存在,程序的配置什么的都没问题啊,一头雾水......通过top命令查看服务器的性能状况如下: [[email prote

Linux下如何查看高CPU占用率线程 LINUX CPU利用率计算

目录(?)[-] proc文件系统 proccpuinfo文件 procstat文件 procpidstat文件 procpidtasktidstat文件 系统中有关进程cpu使用率的常用命令 ps 命令 top命令 单核情况下Cpu使用率的计算 基本思想 总的Cpu使用率计算 计算方法 某一进程Cpu使用率的计算 计算方法 实验数据 某一线程Cpu使用率的计算 计算方法 实验数据 多核情况下cpu使用率的计算 实验一 描述 数据一 数据二 实验二 描述 数据一 数据二 主要问题 Java 系统