记一次 .NET 某智能交通后台服务 CPU爆高分析
一:背景
1. 讲故事
前天有位朋友加微信求助他的程序出现了CPU爆高的问题,开局就是一个红包,把我吓懵了!
由于是南方小年,我在老家张罗处理起来不方便,没有第一时间帮他处理,朋友在第二天上午已经找出问题了,反馈说是一个 while(true)
导致的,这就有点意思了,在我分析的众多 CPU 爆高案例中,还真没遇到 while(true)
的情况,一直都抱有遗憾,真是运气好,年前赶上了,哈哈 。
接下来我们就用 windbg 一起来分析下吧。
二:Windbg 分析
1. 查看CPU占用率
一直关注我的朋友都知道,用 !tp
命令就可以了。
0:022> !tp
CPU utilization: 95 Unknown format characterUnknown format control characterWorker Thread: Total: 11 Running: 11 Idle: 0 MaxLimit: 32767 MinLimit: 4
Work Request in Queue: 0
--------------------------------------
Number of Timers: 3
--------------------------------------
Completion Port Thread:Total: 4 Free: 4 MaxFree: 8 CurrentLimit: 4 MaxLimit: 1000 MinLimit: 4
上面有一句 Unknown format characterUnknown format control characterWorker
显得不太和谐,其实就是 %
的意思,不知道为啥在 .NETCore 会出现这种编码问题 ,接下来我们用 !eeversion
看一下。
0:022> !eeversion
4.700.21.56803 (3.x runtime) free
4,700,21,56803 @Commit: 28bb6f994c28bc91f09bc0ddb5dcb51d0f066806
Workstation mode
In plan phase of garbage collection
SOS Version: 5.0.4.36902 retail build
从基本信息看,当前是 .netcore 3.x
版本,而且很明显看到当前 GC 处于计划阶段。那何为计划阶段呢?
2. 何为计划阶段
简而言之,计划阶段的GC需要决定当前的的托管堆是做简单的标记free操作,还是要做重量级的压缩操作,如果要压缩处理,还需要涉及到托管堆对象的重定位,这往往会耗费相当多的 CPU 时间片,接下来要探究的是什么导致了 GC 触发?
3. GC 触发原因
由于 GC 的触发往往是用户线程
分配数据导致的,在GC触发的整个执行流中,其中有一环就是冻结 CLR执行引擎
,也就是 SuspendEE
,可以在 gc.app
中一探究竟。
为什么一定要提 SuspendEE
呢?是因为我可以通过 !t -special
找出那个 SuspendEE
的线程,这样准确度更高一点。
0:072> !t -special
ThreadCount: 54
UnstartedThread: 0
BackgroundThread: 40
PendingThread: 0
DeadThread: 1
Hosted Runtime: no
OSID Special thread type
1 6328 DbgHelper
2 35c0 Finalizer
4 5aac Timer
5 38b0 ThreadpoolWorker
17 3530 ThreadpoolWorker
18 4484 ThreadpoolWorker
19 1e4c ThreadpoolWorker
21 6380 ThreadpoolWorker
44 5bc4 SuspendEE
52 8ac ThreadpoolWorker
54 4164 ThreadpoolWorker
56 61c8 ThreadpoolWorker
58 1fa4 ThreadpoolWorker
60 2788 ThreadpoolWorker
69 48f4 IOCompletion
70 5708 IOCompletion
71 3b58 ThreadpoolWorker
72 17a0 GC
73 2f00 Gate
74 35e8 IOCompletion
75 5730 IOCompletion
可以看到当前的 44
号线程就是触发 GC 的线程,接下来就明朗了,看看 44 号线程在做啥?切到 44 号线程,然后 !clrstack
即可。
0:044> !clrstack
OS Thread Id: 0x5bc4 (44)
Child SP IP Call Site
000000A2B0C3E4C8 00007ffd471ead3a [HelperMethodFrame: 000000a2b0c3e4c8]
000000A2B0C3E5E0 00007ffce8b4e506 System.Collections.Generic.List`1[[System.__Canon, System.Private.CoreLib]].System.Collections.Generic.IEnumerable.GetEnumerator() [/_/src/System.Private.CoreLib/shared/System/Collections/Generic/List.cs @ 585]
000000A2B0C3E630 00007ffce85e7a10 xxx.Program.DeletexxxExipredDate()
000000A2B0C3E780 00007ffd46bc1f0b System.Threading.ThreadHelper.ThreadStart_Context(System.Object) [/_/src/System.Private.CoreLib/src/System/Threading/Thread.CoreCLR.cs @ 44]
000000A2B0C3E7B0 00007ffd46bb90b6 System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object) [/_/src/System.Private.CoreLib/shared/System/Threading/ExecutionContext.cs @ 172]
000000A2B0C3E830 00007ffd46ba535b System.Threading.ThreadHelper.ThreadStart() [/_/src/System.Private.CoreLib/src/System/Threading/Thread.CoreCLR.cs @ 93]
000000A2B0C3EA48 00007ffd47236c93 [GCFrame: 000000a2b0c3ea48]
000000A2B0C3ECB0 00007ffd47236c93 [DebuggerU2MCatchHandlerFrame: 000000a2b0c3ecb0]
从输出信息看,问题出在了 DeletexxxExipredDate()
方法,接下来探究下这个方法的源码。
private static void DeletexxxExipredDate()
{
while (true)
{
foreach (string key in xxx.xxxSpeedLimit.Keys)
{
try
{
string[] array = xxx.xxxSpeedLimit[key].Split('$');
if (array.Length > 1)
{
DateTime dateTime = Convert.ToDateTime(array[1]);
if ((DateTime.Now - dateTime).TotalSeconds > 21600.0 && xxx.xxxSpeedLimit.ContainsKey(key))
{
xxx.xxxSpeedLimit.TryRemove(key, out var _);
}
}
}
catch (Exception ex)
{
LogHelper.WriteAppExceptionLog("删除数据出现异常:" + ex.Message, ex);
}
Thread.Sleep(20000);
}
}
}
如果有丰富踩坑经验的朋友,我相信一眼就能看出这代码中存在的问题,对,就是当 xxxSpeedLimit
字典为空的时候,就相当于一个 while(true)
死循环啦,对不对?
为了验证我的说法,可以用 !dso
找到 dict 的内存地址,然后用 !wconcurrentdict
即可。
0:044> !dso
OS Thread Id: 0x5bc4 (44)
RSP/REG Object Name
...
000000A2B0C3E708 000001ba8007f618 System.Collections.Concurrent.ConcurrentDictionary`2[[System.String, System.Private.CoreLib],[System.String, System.Private.CoreLib]]
000000A2B0C3E760 000001ba88501cd0 System.Collections.Generic.List`1+Enumerator[[System.String, System.Private.CoreLib]]
000000A2B0C3E768 000001ba80050ec0 System.Threading.ContextCallback
000000A2B0C3E7F8 000001ba80a1a818 System.Threading.Thread
000000A2B0C3EA28 000001ba80a1a898 System.Threading.ThreadStart
0:044> !wconcurrentdict 000001ba8007f618
Empty ConcurrentDictionary
可以看到,当前就是一个 空字典
三:总结
这次事故的主要原因:编码人员缺少了一定的编程经验,在写业务逻辑的时候缺少了对 空字典
的流程处理,导致了 while(true)
的尴尬,也有可能是将那个 Thread.Sleep(20000)
放错了位置
总的来说很感谢这位朋友提供的dump,让我真的眼见为实啦!
记一次 .NET 某智能交通后台服务 CPU爆高分析的更多相关文章
- 记一次 .NET 某消防物联网 后台服务 内存泄漏分析
一:背景 1. 讲故事 去年十月份有位朋友从微信找到我,说他的程序内存要炸掉了...截图如下: 时间有点久,图片都被清理了,不过有点讽刺的是,自己的程序本身就是做监控的,结果自己出了问题,太尴尬了 二 ...
- 记一次 .NET 车联网云端服务 CPU爆高分析
一:背景 1. 讲故事 前几天有位朋友wx求助,它的程序CPU经常飙满,没找到原因,希望帮忙看一下. 这些天连续接到几个cpu爆高的dump,都看烦了,希望后面再来几个其他方面的dump,从沟通上看, ...
- 记一次 .NET 某智慧物流 WCS系统 CPU 爆高分析
一:背景 1. 讲故事 哈哈,再次见到物流类软件,上个月有位朋友找到我,说他的程序出现了 CPU 爆高,让我帮忙看下什么原因,由于那段时间在苦心研究 C++,分析和经验分享也就懈怠了,今天就给大家安排 ...
- 记一次 .NET 某娱乐聊天流平台 CPU 爆高分析
一:背景 1.讲故事 前段时间有位朋友加微信,说他的程序直接 CPU=100%,每次只能手工介入重启,让我帮忙看下到底怎么回事,哈哈,这种CPU打满的事故,程序员压力会非常大, 我让朋友在 CPU 高 ...
- 记一次 .NET 某电商交易平台Web站 CPU爆高分析
一:背景 1. 讲故事 已经连续写了几篇关于内存暴涨的真实案例,有点麻木了,这篇换个口味,分享一个 CPU爆高 的案例,前段时间有位朋友在 wx 上找到我,说他的一个老项目经常收到 CPU > ...
- 记一次 .NET 某物管后台服务 卡死分析
一:背景 1. 讲故事 这几个月经常被朋友问,为什么不更新这个系列了,哈哈,确实停了好久,主要还是打基础去了,分析 dump 的能力不在于会灵活使用 windbg,而是对底层知识有一个深厚的理解,比如 ...
- 记一次 .NET 差旅管理后台 CPU 爆高分析
一:背景 1. 讲故事 前段时间有位朋友在微信上找到我,说他的 web 系统 cpu 运行一段时候后就爆高了,让我帮忙看一下是怎么回事,那就看吧,声明一下,我看 dump 是免费的,主要是锤炼自己技术 ...
- 记一次 .NET游戏站程序的 CPU 爆高分析
一:背景 1. 讲故事 上个月有个老朋友找到我,说他的站点晚高峰 CPU 会突然爆高,发了两份 dump 文件过来,如下图: 又是经典的 CPU 爆高问题,到目前为止,对这种我还是有一些经验可循的. ...
- 记一次 .NET 某医院HIS系统 CPU爆高分析
一:背景 1. 讲故事 前几天有位朋友加 wx 抱怨他的程序在高峰期总是莫名其妙的cpu爆高,求助如何分析? 和这位朋友沟通下来,据说这问题困扰了他们几年,还请了微软的工程师过来解决,无疾而终,应该还 ...
随机推荐
- 【LeetCode】513. Find Bottom Left Tree Value 解题报告(Python & C++ & Java)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 BFS DFS Date 题目地址:https:// ...
- 移动端H5-iPhone安全距离适配
安全区域? 安全区域指的是一个可视窗口范围,处于安全区域的内容不受圆角(corners).齐刘海(sensor housing).小黑条(Home Indicator)影响,如下图蓝色区域: 也就是说 ...
- Codeforces1132A——Regular Bracket Sequence(水题)
Regular Bracket Sequence time limit per test:1 second memory limit per test:256 megabytes input:stan ...
- 《机器学习实战》kNN算法及约会网站代码详解
使用kNN算法进行分类的原理是:从训练集中选出离待分类点最近的kkk个点,在这kkk个点中所占比重最大的分类即为该点所在的分类.通常kkk不超过202020 kNN算法步骤: 计算数据集中的点与待分类 ...
- CS5211与PS8625参数差异|CS5211完全兼容PS8625|普瑞PS8625替代
PS8625是一个DP显示端口 到LVDS转换器芯片,利用GPU和显示端口(DP) 或嵌入式显示端口(eDP) 输出和接受LVDS输入的显示面板.PS8625实现双通道DP输入,双链路LVDS输出.P ...
- 使用 JavaScript 的 HTML 页面混合、根据在下拉列表框中选择的内容,决定页面效果,用户在下拉列表框中选择页面将要使用的背景颜色
查看本章节 查看作业目录 需求说明: 根据在下拉列表框中选择的内容,决定页面效果 用户在下拉列表框中选择页面将 要使用的背景颜色 当用户选择橙色时,页面背景将显示为橙色 实现思路: 用表单 <s ...
- 【MySQL作业】MySQL函数——美和易思字符串函数应用习题
点击打开所使用到的数据库>>> 1.将所有客户的姓名与电话以"-"作为分隔符进行连接显示. 使用 concat(s1,s2,-) 函数将所有客户的姓名与电话以&q ...
- Swoole 进程管理模块 Process 之单进程的使用
PHP 自带的 pcntl,存在很多不足,如: 没有提供进程间通信的功能: 不支持重定向标准输入和输出: 只提供了 fork 这样原始的接口,容易使用错误: Swoole\Process 提供了如下特 ...
- CSS基础-4 定位
CSS定位和浮动 css定位:改变页面的位置 定位机制有以下三种 普通流 浮动 绝对布局 定位的属性: position:把元素放在一个静态的.相对的.绝对的.或固定的位置中 top ...
- centos6.5-Apache优化
Apache的网页压缩功能 一.配置网页压缩功能 在配置压缩功能以前访问网页的响应头部 Response Headers view source Accept-Ranges:bytes Connect ...