Dictionary导致CPU暴涨

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Dictionary导致CPU暴涨相关的知识,希望对你有一定的参考价值。

中午吃完饭回来,刚想眯一会,突然发现公司预警群报警,某台机器CPU100%,连续三次报警,心里咯噔一下,我新开发的程序就在这上面,是不是我的程序导致的?立马远程,oh my god,果然是。 二话不说,抓紧抓dump,由于是生产环境,所以只抓了两个dump,中间间隔一分钟,立马程序重启。

首先,这个程序从发布以来,cpu从来没有占用如此之高,已经稳定运行近一周时间,期间出现的内存暴涨问题也是由于业务垃圾数据未及时清理,那么唯一的可能性就是早上为了方便查看运行状态,增加的一个小功能导致的,凡事都要讲证据,还是抓紧分析一下dump吧。

常规思路:比较两个dump,查看是否有线程时间持续增长,进而确定下一步的方案。

打开windbg,打开第一个dump,.loadby sos clr后,先看一下线程池,输入!threadpool

技术分享

可以看到,目前cpu占用率92%,目前活动线程25个,由于是数据分析程序,线程稍多一点

然后输入 !runaway 看下各个线程的执行时间吧

技术分享

这里就有问题了,看到很多线程执行时间都在好几分钟,作为程序开发者,我感觉肯定是不应该的,因为分析过程都极度细化,每个线程的执行时间都不会超过10秒,先不管了,看下第二个dump对比下吧。

打开第二个dump,.loadby sos clr,然后 !runaway,突然发现没有出现熟悉的画面,

技术分享

这就很尴尬了,常规的手段没法玩了,难道是当时紧张,抓的dump也紧张了?

既然没法比较,那就只能从第一个dump的场景去分析了,首先看第一个执行了18分钟的线程,输入~10s,然后输入!clrstack

技术分享

可以看到这是接收Kafka数据源的,由于一直在不停接收,执行时间会相对较长,看下一个:

技术分享

在执行一个dictionary的insert操作,这种东西不是该秒完的么?并且这玩意一看就是早上新加的,心里不由咯噔一下,再继续找其他的线程,果然其他线程也都在执行这个代码。我靠,看来是多线程环境下没有使用ConcurrentDictionary而使用Dictionary导致的线程并发问题了?在我的意识里面,这种线程不安全的类,不该只是数据会有问题么,还会导致高CPU?看样子,应该是多个线程都在同时insert,竞争某个资源,导致死锁?可是这时候不该是CPU低么?应该是都在频繁的执行什么东西吧,并且一直执行不完,从而引发CPU暴涨。不管了,解决问题先,看一下我的源代码吧:

技术分享

由于不断的线程都在执行这个操作,并且没有加锁,所以导致以上问题,换为ConcurrentDictionary,问题解决。首先总结一下,在高并发环境下,首先要考虑的是Concurrent下面的线程安全类,个人在很多关键的集合上都使用了,但是这个辅助分析的集合认为数据并不重要,只要能大体反应运行状况即可,所以偷懒直接用了Dictionary,结果导致少了一个午休,真是得不偿失!

不过还得继续寻根问底啊。看看Dictionary的Add的时候,到底做了啥操作,会导致死锁或者高CPU,而不仅仅是数据不安全,首先定位到Add方法,

技术分享,看到调用内部的Insert,也就是我们dump中看到的,继续

技术分享

哎呀,这个玩意就有点复杂了,究竟哪里会导致高CPU呢?除非for循环一直结束不了,再翻翻别人的文章,发现这么一段话,是Dictionary的Find方法导致cpu高的,

技术分享

在多线程情况下,有可能进入死循环,但是具体哪里不清楚,留待后续解决吧。如果大牛们知道,还望赐教!

 

以上是关于Dictionary导致CPU暴涨的主要内容,如果未能解决你的问题,请参考以下文章

C# - Dictionary 和 Object[] 之间的三元运算符

Mybatis 并发执行导致cpu占满的问题

将 [Dictionary<String,Any?>] 转换为 [Dictionary<String,Any!>] ?迅速 3

云主机被拿去挖矿,cpu暴涨,tcp连接突增

分析一个 .NET 写的 某 RFID标签系统 CPU暴涨

windbg分析一次大查询导致的内存暴涨