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

前言

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

如何判断是否有死循环?

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

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

  • 通过CPU占用率来判断。

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

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

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

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

1. process explorer

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

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

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

使用process explorer

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

2. windbg

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

  • 使用.ttime命令

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

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

    获取所有线程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的命令。如果哪位小伙伴有更好的办法,请一定要留言告诉我!

下面是我用Parallel Stacks功能排查高CPU占用率的屏幕录像。

小提示:Ctrl + Alt + p可以快速打开附加进程界面。

小结

以上三种工具,我会先使用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 实战指南》

猜你喜欢:

[原]调试实战——使用windbg调试崩溃在ole32!CStdMarshal::DisconnectSrvIPIDs

[原]调试实战——崩溃在ComFriendlyWaitMtaThreadProc

[原]调试实战——调试PInvoke导致的内存破坏

[原]调试实战——调试excel启动时死锁

[原]调试实战——调试TerminateThread导致的死锁

[原]调试实战——调试DLL卸载时的死锁

[原]排错实战——拯救加载调试符号失败的IDA

[原]排错实战——使用process explorer替换任务管理器

[原]排错实战——VS清空最近打开的工程记录

[原]排错实战——解决Tekla通过.tsep安装插件失败的问题

[原]排错实战——你知道拖动窗口时只显示虚框怎么设置吗?

[原]排错实战——通过对比分析sysinternals事件修复程序功能异常

你知道怎么使用DebugView查看调试信息吗?

欢迎留言交流

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/312610.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

蓝桥杯 迷宫

参考代码&#xff1a; #include<bits/stdc.h> using namespace std; typedef long long ll; int e[55][55], vis[55][55]; //e矩阵表示障碍物信息&#xff0c;vis矩阵表示点是否被访问过 int m 30, n 50; struct node{ //定义结构体&#xff0c;用于存放点的信息 i…

ASP.NET Core基于K8S的微服务电商案例实践--学习笔记

摘要一个完整的电商项目微服务的实践过程&#xff0c;从选型、业务设计、架构设计到开发过程管理、以及上线运维的完整过程总结与剖析。讲师介绍产品需求介绍纯线上商城线上线下一体化跨行业跨商业模式从0开始&#xff0c;我们应该采用微服务吗&#xff1f;不适合采用微服务架构…

蓝桥杯 日志统计 尺取

参考代码&#xff1a; #include<bits/stdc.h> using namespace std; typedef long long ll; vector<int> v[100005]; //定义容器用于存放第i篇帖子被点赞的时间 int main() {ios::sync_with_stdio(false); int n, d, k;cin >> n >> d >> k;in…

2019 ASP.NET Core 之微调查报告,新鲜出炉

▼更多精彩推荐&#xff0c;上午11点到达▼在本周三的时候&#xff0c;因为直播没有找到合适内容的缘故&#xff0c;因此在我的公众号内发起了一波问卷调查&#xff0c;地址是&#xff1a;【壹个问卷】NetCore学习的知识点调查&#xff0c;当时就是想着有十来份儿就已经很给面子…

蓝桥杯 子串分值

参考代码&#xff1a; #include<bits/stdc.h> using namespace std;int main() {ios::sync_with_stdio(false); string str;cin >> str;int sum 0;int left, right;char s;int len str.size();for(int i 0; i < len; i) //依次循环每一个字符&#xff0c;…

基于 Blazui 的 Blazor 后台管理模板 BlazAdmin 正式尝鲜

简介BlazAdmin 是一个基于Blazui的后台管理模板&#xff0c;无JS&#xff0c;无TS&#xff0c;非 Silverlight&#xff0c;非 WebForm&#xff0c;一个标签即可使用。  我将在下一篇文章讨论 Blazor 服务器端渲染与客户端渲染的基本原理&#xff0c;对比服务器端渲染与 WebFo…

蓝桥杯 123 二分+打表

参考代码&#xff1a; #include<bits/stdc.h> using namespace std; typedef long long ll; ll temp[1500000], sum[1500000]; //temp数组记录序号和&#xff0c;sum数组记录前缀和 ll cal(ll n) //计算自然数求和 {return (n1)*n/2; }int main() {ios::sync_with_s…

.Net Core使用Ocelot网关(二) -鉴权认证

前言上一章.Net Core使用Ocelot网关(一) -负载,限流,熔断,Header转换 已经简单的介绍了ocelot的使用了,但是网关暴露的接口如果什么人都能访问的话安全性就太低啦。所以我们需要去鉴权和认证。这里我们使用identityServer4给我们的网关来鉴权认证。创建Identity服务我们创建一个…

蓝桥杯 k倍区间 前缀和

参考代码&#xff1a; #include<bits/stdc.h> using namespace std; typedef long long ll; int array[100005], t[100005]; //array记录每个元素值&#xff0c;t记录取余k&#xff0c;各余数对应前缀和的数量 int main() {ios::sync_with_stdio(false); ll sum 0, c…

Kubernetes 的2020年“野望”

Kubernetes是一个用于部署容器化应用程序的开源容器编排系统&#xff0c;由Alphabet的GOOGL Google部门设计&#xff0c;其发展势头强劲&#xff0c;这得益于全球企业以指数级的速度生成数据之大势。Kubernetes支持在单个OS上无缝部署多个应用程序并实现诸如监视、调度、扩展这…

微服务的时间和成本去哪儿了

2019 中国.NET 开发者峰会目前在国内的.NET社区还是很有影响力的&#xff0c;宣传的内容也都是比较新潮和前言的技术栈。有一个不争的现实是基本上主题都是关于.NET Core的&#xff0c;以及基于该主题之上的延展。比如ML.NET相关的机器学习&#xff1b;基于.NET Core的微服务实…

自定义滚动条(Custom ScrollBar)

时间如流水&#xff0c;只能流去不流回&#xff01; 点赞再看&#xff0c;养成习惯&#xff0c;这是您给我创作的动力&#xff01; 本文 Dotnet9 https://dotnet9.com 已收录&#xff0c;站长乐于分享dotnet相关技术&#xff0c;比如Winform、WPF、ASP.NET Core等&#xff0c;亦…

用ASP.NET Core构建可检测的高可用服务--学习笔记

摘要随着现代化微服务架构的发展&#xff0c;系统故障的定位与快速恢复面临着诸多挑战&#xff0c;构建可检测的服务&#xff0c;帮助线上保障团队时刻掌控应用的运行状况越来越重要。本次分享会讲解如何让 ASP .NET Core 应用与现代化云基础设施完美融合&#xff0c;提升服务的…

[功能发布]Excel催化剂2周年巨献-网页数据采集功能发布,满足90%合理场景使用...

转眼间&#xff0c;Excel催化剂推出已经两周年&#xff0c;在此之际&#xff0c;献上数据时代最刚需的网页采集功能&#xff0c;无需苦苦寻觅各种工具&#xff0c;借助Excel催化剂过往数据处理、清洗功能&#xff0c;加上此轮的网页采集功能&#xff0c;一点不输于市面上的各种…

.NET Core 微服务学习与实践系列文章目录索引(2019版)

Photo &#xff1a;.NET Core文 | Edison Zhou2018年&#xff0c;我开始学习和实践.NET Core&#xff0c;并开始了微服务的学习&#xff0c;以及通过各种开源组件搭建服务治理技术方案&#xff0c;并在学习过程中总结了一个.NET Core微服务学习与实践系列文章&#xff0c;涵盖了…

dapr微服务.net sdk入门

Actors入门先决条件.Net Core SDK 3.0Dapr CLIDapr DotNet SDK概述本文档描述如何在客户端应用程序上创建Actor&#xff08;MyActor&#xff09;并调用其方法.MyActor --- MyActor.Interfaces|- MyActorService|- MyActorClient接口项目&#xff08;\MyActor\MyActor.Interface…

TPL Dataflow组件应对高并发,低延迟要求

长话短说2C互联网业务增长&#xff0c;单机多核的共享内存模式带来的排障问题、编程困难&#xff1b;随着多核时代和分布式系统的到来&#xff0c;共享模型已经不太适合并发编程&#xff0c;因此actor-based模型又重新受到了人们的重视。---------------------------调试过多线…

abp模块生命周期设计思路剖析

abp中将生命周期事件抽象为4个接口&#xff1a;//预初始化 public interface IOnPreApplicationInitialization {void OnPreApplicationInitialization([NotNull] ApplicationInitializationContext context); }//初始化 public interface IOnApplicationInitialization {void …

.Net Core + 微信赋能企业级智能客服系统--学习笔记

摘要围绕目前需求猛增的微信及移动端企业智能客服业务&#xff0c;利用 .NET Core 的一系列优秀特性及 SignalR 模块打造全双工、跨微信/QQ/钉钉等应用平台、跨系统平台、跨终端、支持企业级并发的移动端客服系统。讲师介绍目录微信应用生态简介微信小程序基础通讯原理Senparc.…

基于docker-compose的Gitlab CI/CD实践排坑指南

长话短说经过长时间实操验证&#xff0c;终于完成基于Gitlab的CI/CD实践&#xff0c;本次实践的坑位很多&#xff0c; 实操过程尽量接近最佳实践&#xff08;不做hack, 不做骚操作&#xff09;&#xff0c;记录下来加深理解。看过博客园《docker-compose真香》一文的园友留意到…