再记一次w3wp占用CPU过高的解决过程(Dictionary和线程安全)-程序员宅基地

技术标签: 操作系统  

在此之前项目有发生过两次类似的状况,都得以解决,但最近又会发现偶尔CPU会跑满,虽然之前使用过WinDbg解决过两次问题但人的记忆是不可靠的,今天处理同样问题的时候还是遇到了一些障碍,这一次希望可以记录的更全面些。

上两次的博文链接:记一次w3wp占用CPU过高的解决过程(Dictionary和线程安全)EntityFramework中的线程安全,又是Dictionary

首先请大家不要喷我,因为这一次还是关于Dictionary的一些低级错误,我自己看到都无语了。。。

抓取Dump

使用任务管理器抓取Dump,如果操作系统较低可以使用“Process Explorer”。

image

使用WinDbg分析

1.使用WinDbg打开dump文件。

2.加载sos.dll

命令:.loadby sos clr

image

3.查看相关线程信息

命令:!threads –special

special参数会将由CLR创建的特殊线程单独列出便于减少线程的排查工作。

image

红框圈出的是我们要重点排查的线程(工作者线程),至于其它的则是一些CLR自拥有的一些线程,如:GC线程、对象释放线程、计时器线程、I/O线程等。

线程类型的名称翻译:

  • GC:垃圾回收线程
  • Finalizer:对象释放线程,.Net至少有一个,用于专门处理对象释放。
  • Timer:计时器线程
  • ThreadpoolWorker:工作者线程
  • IOCompletion:I/O线程

4.查看具体线程堆栈

命令:~{ThreadId}s、!clrstack

~{ThreadId}s:将当前上下文切换到指定的线程内

image

!clrstack:得到当前的线程的堆栈信息

image

第二个红框的前两句太长了,我复制在下面:

000000d784afe180 000007fda1efa328 System.Collections.Generic.Dictionary`2[[System.__Canon, mscorlib],[System.Collections.Generic.KeyValuePair`2[[System.__Canon, mscorlib],[System.Boolean, mscorlib]], mscorlib]].FindEntry(System.__Canon)
000000d784afe1f0 000007fda1ef96eb System.Collections.Generic.Dictionary`2[[System.__Canon, mscorlib],[System.Collections.Generic.KeyValuePair`2[[System.__Canon, mscorlib],[System.Boolean, mscorlib]], mscorlib]].TryGetValue(System.__Canon, System.Collections.Generic.KeyValuePair`2<System.__Canon,Boolean> ByRef)

可以发现,是在TryGetValue方法时堵塞了,而看到红框中的最后一句则可以发现是EnumParseCacheHelper的Parse方法出了问题,这个方法主要是对枚举转换的一个缓存处理以提升性能。

为了再次确认问题,我继续对19、20、21、24等线程进行了查看,都是在这里堵塞了,那么问题浮出水面了,下面就去看代码,并且解决它。

解决问题

找到对应的代码:

image

问题显而易见,CacheDictionary是一个全局静态的字段,而我在下面方法使用它的时候丝毫没有注意并发下的情况,没有加锁来保证线程安全。。看到这感觉不可思议怎么犯这么低级的错误。。。

解决它方式:

image

解决方式很简单,使用了.NET4提供的线程安全的字典:ConcurrentDictionary。

关于这一次问题的思考

Dictionary为什么这么容易堵塞

这边引用之前的博文内容:

我知道Dictionary不是一个线程安全的类型,但我原本以为Dictionary在非线程安全方式下访问时数据会错乱,而不会堵塞或者死锁,而这次的这个问题让我感觉到讶异,为什么Add一个项目会造成堵塞?

反编译Dictionary的源码后发现异常的复杂,也没有细究,所以下面的一段描述大家抱有自己的想法去阅读,可能是错的也可能是对的。

image

image

上面是我认为存在问题的地方,当一个线程执行过Initialize后buckets数组的值被修改,而第二个线程同时进入了Initialize方法,那么第一个线程所维护的值被破坏,造成在算法环节出现了死循环,这也可以说明了为什么cpu有时候是50%有时候是99%的问题。

当前有多少个线程发生了这种状态,如果发生这种状态的线程越多则代表cpu占用越多。

这次问题的经验:以后在使用集合或字典时首先应该先想到System.Collections.Concurrent命名空间,虽然它的性能在正常情况下低于普通的Dictionary,但那么几十或者几百毫秒的损失对于稳定性来说微不足道,也减少了问题的发生。

写在最后

因为Rabbit.WeiXin是一个开源项目当然第一件事情就是发布更新。。避免更多的人出现此问题。

image

交流方式

QQ群:384413261(RabbitHub)

Email:[email protected]

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_33909059/article/details/85772833

智能推荐

(一)使用YOLOv3训练BDD100K数据集之数据集下载-程序员宅基地

文章浏览阅读1.9w次,点赞26次,收藏156次。目录1 数据集下载2 数据集简单分析3 标签文件分析1 数据集下载之前博客写 了如何使用YOLOv3训练自动驾驶数据集KITTI,它的图片尺寸普遍为1242x375(大约),且总共有提供标签的7481张训练集,还有未提供标签的7518张测试集,用于官方评测算法。如果我们自己要评测算法,需要从7481张训练集中划分一部分作为验证集,这样训练的数据又减少了。而BDD00K数据集总共拥有1..._bdd100k数据集

pgsql sql中获取当前时间_PostgreSQL技巧 如何获取当前日期时间-程序员宅基地

文章浏览阅读8.1k次,点赞2次,收藏3次。这篇文章主要介绍了PostgreSQL 如何获取当前日期时间及注意事项,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧在开发数据库应用或者调试代码时,经常需要获取系统的当前日期和时间,我们来看一下 PostgreSQL 中提供的相关函数。当前日期CURRENT_DATECURRENT_DATE 函数用于获取数据库服务器的当前日期..._pg获取当前时间

告别 996,解放开发者,一站式 AI 开发平台助力 AI-Native 时代_ai-native开发框架-程序员宅基地

文章浏览阅读4.9k次,点赞3次,收藏4次。当前,AI 赋能千行百业的愿景仍然处于起步阶段,AI 在很多时候更被认为是很高深需要非常大投入的技术领域,但是 AI 的超高技术门槛给 AI 应用的落地带来了极大的困难。根据波士顿咨询公司的调研报告,约86% 的市场需求需要定制开发业务场景下的 AI 模型。定制模型过程中,企业用户和开发者往往会面临缺少模型训练经验、数据采集和标注成本较高、模型适配与部署流程较为繁琐、模型优化迭代周期长等核心难点,从而会造成整个项目的成本高、周期长、且在前期对项目效果无法准确预期。由于AI 应用开发的成本高昂,市.._ai-native开发框架

CSUST OJ 2020_oj 有x个瓶盖-程序员宅基地

文章浏览阅读237次。这题啊,傻逼题首先因为想看看大家的思维和写法,并没有针对题目进行数据加强,所以基本上怎么暴力写都能过其实这题是由一个很经典的题目扩展而来的。即:你有a个瓶盖,b个瓶盖能换一瓶可乐,问你最多能喝多少瓶可乐。但这题稍微负责一些,因为瓶子和瓶盖换的新可乐,有一个瓶盖和瓶子,所以会相互影响。所以我们每次算出瓶子和瓶盖分别能换多少可乐,然后再更新瓶子和瓶盖的数量就行了。所以针对数据氛围,暴力就..._oj 有x个瓶盖

Vue项目搭建常用的配置文件,request.js和vue.config.js_interceptors.request.use 没有config-程序员宅基地

文章浏览阅读6.4w次,点赞248次,收藏1k次。笔记_interceptors.request.use 没有config

OpenShift 4.5 新特性 - 创建任务和定时任务_openshift cronjob-程序员宅基地

文章浏览阅读1.1k次。文章目录通过YAML创建创建Job创建CronJob使用命令创建Job创建CronJob在Kubernetes中分贝使用Job和CronJob实现一次性运行的任务和定时运行的的任务,他们分别被Kubernetes的JobController和CronJobController控制器所控制,而这些任务都是通过Pod运行的。在创建Job和CronJob对象的时候,既可以使用定义对象的YAML文件,还可使用命令直接创建。需要注意的是,从OpenShift 4.5开始,在使用oc命令创建Job和CronJob对_openshift cronjob

随便推点

RouterLink在IE和Firefox中不起作用(路由不跳转)的问题-程序员宅基地

文章浏览阅读1k次。方法一:只用a标签,不适用button标签;方法二:使用button标签和Router.navigate方法_routerlink在ie和firefox中不起作用

vue.js 和 vue.min.js 文件_vue.js vue.min.js-程序员宅基地

文章浏览阅读9.9k次。https://download.csdn.net/download/qq_36688143/10546461_vue.js vue.min.js

mysql5.7.20出现The server time zone value '�й���׼ʱ��' is unrecogni。。。。的解决办法-程序员宅基地

文章浏览阅读1.3w次,点赞4次,收藏12次。java.sql.SQLException: The server time zone value '�й���׼ʱ��' is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the serverTimezone configu...

GitLab配置ssh-key_gitlab更新ssh-key-程序员宅基地

文章浏览阅读1.9k次。1 背景当前很多公司都选择git作为代码版本控制工具,然后自己公司搭建私有的gitlab来管理代码,我们在clone代码的时候可以选择http协议,当然我们亦可以选择ssh协议来拉取代码。但是网上很少找到如何用git客户端生成ssh key,然后配置在gitlab,我当时在做的时候苦于摸索,后来终于找到了解决方案,那么本文,我们就来聊一聊如何本地git客户端生成ssh key,然后配置在gitlab里,而后使用ssh协议进行提交和拉取git远程仓库的代码。2 解决方案打开本地git bash,使用_gitlab更新ssh-key

计算机网络考试试题库-期末考试题库含答案_某公司 testa 有一个总部和三个下属工厂。总部有 4 个局域网,其 中 lan2-lan4 都-程序员宅基地

文章浏览阅读1.2w次,点赞33次,收藏332次。一、选择题(第一章 1-10;第二章 11-20;第三章21-35;第四章36-60 ;第五章 61-73道;第六章 74-84道;第七章85-90;第九章91-95;第十章96-100)1.下列四项内容中,不属于Internet(因特网)基本功能是____D____。A.电子邮件 B.文件传输 C.远程登录 D.实时监测控制2.Internet是建立在____C_____协议集上的国际互联网络。 A.IPX B.NetBEUI C.TCP/IP _某公司 testa 有一个总部和三个下属工厂。总部有 4 个局域网,其 中 lan2-lan4 都

高通平台GPU动态调频DCVS . 篇1 . Interface_高通 gpu 限频 /sys/class/kgsl/kgsl-3d0/max_pwrlevel-程序员宅基地

文章浏览阅读9.4k次,点赞13次,收藏43次。高通平台的GPU内核驱动架构趋于稳定,代码和接口都具备通用性,故分析整理出来以供快速参考高通平台GPU内核驱动框架全称是 Kernel-Graphics-Support-Layer KGSL1. KGSL kernel interfacekgsl驱动所暴露出来的GPU相关常规控制接口位于 /sys/class/kgsl/kgsl-3d0 路径下/sys/class/kgsl/kgsl-3d..._高通 gpu 限频 /sys/class/kgsl/kgsl-3d0/max_pwrlevel