记一次 .NET 车联网云端服务 CPU爆高分析
一:背景
1. 讲故事
前几天有位朋友wx求助,它的程序CPU经常飙满,没找到原因,希望帮忙看一下。
这些天连续接到几个cpu爆高的dump,都看烦了????????????,希望后面再来几个其他方面的dump,从沟通上看,这位朋友表现的好惨,可能实际更惨,那既然找到我了,我就尽最大能力帮他找到幕后真凶,话不多说,上 windbg。
二:windbg 分析
1. 查看托管线程
因为线程都是靠cpu养着,所以从线程上入手也是一个很好的思路,要想查看程序的所有托管线程,可以使用 !t
命令。
0:000> !t
ThreadCount: 38
UnstartedThread: 0
BackgroundThread: 34
PendingThread: 0
DeadThread: 3
Hosted Runtime: noLock ID OSID ThreadOBJ State GC Mode GC Alloc Context Domain Count Apt Exception0 1 105c 000000000067f600 2a020 Preemptive 0000000000000000:0000000000000000 0000000000671ec0 0 MTA 2 2 13d0 00000000192c4f40 2b220 Preemptive 0000000000000000:0000000000000000 0000000000671ec0 0 MTA (Finalizer)
...
XXXX 15 0 000000001bc64970 8039820 Preemptive 0000000000000000:0000000000000000 0000000000671ec0 0 MTA (Threadpool Completion Port) 24 23 1380 000000001bc660e0 8029220 Preemptive 0000000000000000:0000000000000000 0000000000671ec0 0 MTA (Threadpool Completion Port)
XXXX 53 0 000000001bc63200 8039820 Preemptive 0000000000000000:0000000000000000 0000000000671ec0 0 MTA (Threadpool Completion Port)
XXXX 27 10dc 000000001bd0dbf0 1029220 Preemptive 0000000002CB40F8:0000000002CB4108 0000000000671ec0 1 MTA (GC) (Threadpool Worker)
在卦象上看:程序有38个线程,死了3个,我去,有一个亮点,最后一行出现了一个熟悉的 MTA (GC)
字样,这什么意思呢?这表示当前线程触发了GC,但奇怪的是,这个触发GC的线程死了,你肯定要问怎么看出来的,看行头的 XXXX
,先不管了,死马当活马医,调出线程的所有托管和非托管栈,看看有没有 WaitUntilGCComplete
和 try_allocate_more_space
字样。
2. 查看线程栈
要想查看所有线程的线程栈,可以使用 ~*e !dumpstack
命令。
搜索
WaitUntilGCComplete
关键字。
从图中看,嘿嘿,真的有18个线程在等待,而且还看到了 System.String.Concat
,是不是和我上上篇发的 his
cpu爆高是一个套路?????????????
搜索
try_allocate_more_space
关键字。
我去,竟然没有 try_allocate_more_space
关键词,这就和 his 不是一个套路了,???????????? 有可能这个dump踩的不是特别好的时机,有可能程序正处于某些怪异行为中。
看样子这段路走到头了,不过还是那句话,线程是靠cpu养着的,那就硬着头皮看看各个线程都在做什么吧,为了让结果更清晰一点,换一个命令 ~*e !clrstack
。
从图中可以看出当前有 25 个线程正卡在 FindEntry(System.__Canon)
处,而且从调用堆栈上看,貌似是 aliyun 封装的dll,为什么有这么多的线程卡在这里呢?这就给人一个很大的问号?接下来我就把阿里云的这段代码给导出来看看到底发生了什么。
3. 查看问题代码
要想导出问题代码,还是用经典的 !ip2md + !savemodule
组合命令。
0:000> !ip2md 000007fe9a1a0641
MethodDesc: 000007fe9a5678e0
Method Name: Aliyun.Acs.Core.Utils.CacheTimeHelper.AddLastClearTimePerProduct(System.String, System.String, System.DateTime)
Class: 000007fe9a595a08
MethodTable: 000007fe9a567900
mdToken: 00000000060000a6
Module: 000007fe9a561f58
IsJitted: yes
CodeAddr: 000007fe9a1a0610
Transparency: Critical
0:000> !savemodule 000007fe9a561f58 E:\dumps\AddLastClearTimePerProduct.dll
3 ps in file
p 0 - VA=2000, VASize=14148, FileAddr=200, FileSize=14200
p 1 - VA=18000, VASize=3fc, FileAddr=14400, FileSize=400
p 2 - VA=1a000, VASize=c, FileAddr=14800, FileSize=200
然后用 ILSpy 反编译一下这个dll,因为是阿里云的代码,我就可以放心大胆的放出来啦。
// Aliyun.Acs.Core.Utils.CacheTimeHelper
using System;
using System.Collections.Generic;public class CacheTimeHelper
{private static Dictionary<string, DateTime> lastClearTimePerProduct = new Dictionary<string, DateTime>();private const int ENDPOINT_CACHE_TIME = 3600;public static bool CheckCacheIsExpire(string product, string regionId){string key = product + "_" + regionId;DateTime dateTime;if (lastClearTimePerProduct.ContainsKey(key)){dateTime = lastClearTimePerProduct[key];}else{dateTime = DateTime.Now;lastClearTimePerProduct.Add(key, dateTime);}if (3600.0 < (DateTime.Now - dateTime).TotalSeconds){return true;}return false;}public static void AddLastClearTimePerProduct(string product, string regionId, DateTime lastClearTime){string key = product + "_" + regionId;if (lastClearTimePerProduct.ContainsKey(key)){lastClearTimePerProduct.Remove(key);}lastClearTimePerProduct.Add(key, lastClearTime);}
}
可以看出,上面这段代码在 if (lastClearTimePerProduct.ContainsKey(key))
处走不下去了,如果往下追,可参考 Dictionary 的源码。
public class Dictionary<TKey, TValue>
{// System.Collections.Generic.Dictionary<TKey,TValue>public bool ContainsKey(TKey key){return FindEntry(key) >= 0;}
}
到这里,有没有看出这个 CacheTimeHelper
有什么问题吗?对,竟然在多线程环境下用的是非线程安全的 Dictionary<string, DateTime>
,这就很有问题了。
4. 用 Dictionary 到底会有什么问题
在多线程环境下用 Dictionary
肯定会导致数据错乱,这个毫无疑问,而且还会遇到一些 迭代时异常
,但如果说这个误用会导致 CPU 爆高,在我的视野范围内还没看到过。。。为了确保起见,到 bing 上搜搜这样的 天涯沦落人
。
嘿嘿,还真的有这样的案例:High CPU in .NET app using a static Generic.Dictionary (
https://www.tessferrandez.com/blog/2009/12/21/high-cpu-in-net-app-using-a-static-generic-dictionary.html
),再截个图。
从文章描述看,简直是一摸一样????????????,这也就断定在多线程环境下操作 Dictionary ,可能会导致 FindEntry(key)
时出现死循环,然后 25 个死循环一起把cpu抬起来了,补充一下当前爆满的CPU利用率。。。
0:000> !tp
CPU utilization: 100%
Worker Thread: Total: 27 Running: 27 Idle: 0 MaxLimit: 32767 MinLimit: 4
Work Request in Queue: 0
--------------------------------------
Number of Timers: 1
--------------------------------------
Completion Port Thread:Total: 4 Free: 3 MaxFree: 8 CurrentLimit: 3 MaxLimit: 1000 MinLimit: 4
三:总结
既然是阿里云
的sdk出的bug,这问题就麻烦了。。。改也改不得,然后告诉朋友去提工单解决。
本以为事情就这样结束了,但我想一想,几年前用的阿里云其他 sdk 也遇到了类似CPU爆高的问题,后来通过升级sdk就搞定了,这次也赌赌看,先看一下程序集信息。
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = "")]
[assembly: AssemblyCompany("Alibaba Cloud")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("©2009-2018 Alibaba Cloud")]
[assembly: AssemblyDescription("Alibaba Cloud SDK for C#")]
[assembly: AssemblyFileVersion("1.1.12.0")]
[assembly: AssemblyInformationalVersion("1.1.12")]
[assembly: AssemblyProduct("aliyun-net-sdk-core")]
[assembly: AssemblyTitle("aliyun-net-sdk-core")]
[assembly: AssemblyVersion("1.1.12.0")]
可以看到朋友当前用的是 1.1.12.0
版本,那就把 aliyun-net-sdk-core 升级到最新再看看这个 CacheTimeHelper 有没有被修复 ?
果然不出所料,在新版本中给修复好了,所以经验告诉我,用阿里云的sdk,要记得经常升级,不然各种大坑等着你。。。????????????
END
工作中的你,是否已遇到 ...
1. CPU爆高
2. 内存暴涨
3. 资源泄漏
4. 崩溃死锁
5. 程序呆滞
等紧急事件,全公司都指望着你能解决... 危难时刻才能展现你的技术价值,作为专注于.NET高级调试的技术博主,欢迎微信搜索: 一线码农聊技术,免费协助你分析Dump文件,希望我能将你的踩坑经验分享给更多的人。
记一次 .NET 车联网云端服务 CPU爆高分析相关推荐
- 记一次 .NET 某智能交通后台服务 CPU爆高分析
一:背景 1. 讲故事 前天有位朋友加微信求助他的程序出现了CPU爆高的问题,开局就是一个红包,把我吓懵了!
- 某工控图片上传服务 CPU 爆高分析
一:背景 1.讲故事 今天给大家带来一个入门级的 CPU 爆高案例,前段时间有位朋友找到我,说他的程序间歇性的 CPU 爆高,不知道是啥情况,让我帮忙看下,既然找到我,那就用 WinDbg 看一下. ...
- 记一次 .NET 某电子病历 CPU 爆高分析
一:背景 1.讲故事 前段时间有位朋友微信找到我,说他的程序出现了 CPU 爆高,帮忙看下程序到底出了什么情况?图就不上了,我们直接进入主题. 二:WinDbg 分析 1. CPU 真的爆高吗? 要确 ...
- 记一次 .NET 某资讯论坛 CPU爆高分析
大概有11天没发文了,真的不是因为懒,本想前几天抽空写,不知道为啥最近求助的朋友比较多,一天都能拿到2-3个求助dump,晚上回来就是一顿分析,有点意思的是大多朋友自己都分析了几遍或者公司多年的牛皮藓 ...
- 记一次 .NET 某电商交易平台Web站 CPU爆高分析
一:背景 1. 讲故事 已经连续写了几篇关于内存暴涨的真实案例,有点麻木了,这篇换个口味,分享一个 CPU爆高 的案例,前段时间有位朋友在 wx 上找到我,说他的一个老项目经常收到 CPU > ...
- .NET 某电商交易平台Web站 CPU爆高分析
勘探现场 既然说 CPU > 90%,那我就来验证一下是否真的如此? 0:359> !syncblk Index SyncBlock MonitorHeld Recursion Ownin ...
- 记一次 .NET游戏站程序的 CPU 爆高分析
一:背景 1. 讲故事 上个月有个老朋友找到我,说他的站点晚高峰 CPU 会突然爆高,发了两份 dump 文件过来,如下图: 又是经典的 CPU 爆高问题,到目前为止,对这种我还是有一些经验可循的. ...
- 记一次 .NET 某智慧物流WCS系统CPU爆高分析
一:背景 1. 讲故事 哈哈,再次见到物流类软件,上个月有位朋友找到我,说他的程序出现了 CPU 爆高,让我帮忙看下什么原因,由于那段时间在苦心研究 C++,分析和经验分享也就懈怠了,今天就给大家安排 ...
- 记一次 .NET 某市附属医院 Web程序 偶发性CPU爆高分析
一:背景 1. 讲故事 这个月初,一位朋友加微信求助他的程序出现了 CPU 偶发性爆高,希望能有偿解决一下. 从描述看,这个问题应该困扰了很久,还是医院的朋友给力,开门就是 100块 红包
最新文章
- 考研规划计算机科学与技术,【图片】2020考研,老学长教你如何规划!【计算机考研吧】_百度贴吧...
- python中赋值不正确的_python中的“赋值与深浅拷贝”
- 连接远程mongodb_在centos6.9安装mongodb
- 用C/C++编写window服务
- JZ2440学习总结1
- oracle与mysql的区别总结(一)
- mysql的sql执行过程和explain语句
- 网易编程题-操作序列
- (扫盲)WebSocket 教程
- 【BIEE】14_开发流程介绍
- Windows操作系统的发展历程
- 堆排序(超详细图解 java版)
- flowable设计器自定义自己的人员选择器
- 女神也用的约会决策:决策树算法实践
- Unity内截屏实现
- 四旋翼飞行器基本知识(四旋翼飞行器结构和原理+四轴飞行diy全套入门教程)
- FastGCN: fast learning with graph convolutional networks via importance sampling 论文详解 ICLR 2018
- Leiden算法介绍
- vc++6.0和visual studio 2005
- android 系统数据库Settings属性使用及相关介绍
热门文章
- FusionChart完全入门手册 -2
- DOS命令未公开的命令
- delphi tclientsocket接收不到返回数据_RS—485中教你主站发送报文结构、从站返回报文结构?系列11...
- HTML5+CSS3+JQuery1.9 输入框切换和Div失焦模拟
- 【技术累积】【点】【java】【27】@JSONField
- luogu 1484\1792 种树 奇怪的贪心可反悔
- 《构建之法》 读书笔记
- Web前端笔试面试题汇总(转自github)
- Android中常用到的权限
- VS2008、VS2010中如何屏蔽讨厌的MSVCR*.dll的引用