再记一次w3wp占用CPU过高的解决过程(Dictionary和线程安全)
在此之前项目有发生过两次类似的状况,都得以解决,但最近又会发现偶尔CPU会跑满,虽然之前使用过WinDbg解决过两次问题但人的记忆是不可靠的,今天处理同样问题的时候还是遇到了一些障碍,这一次希望可以记录的更全面些。
上两次的博文链接:记一次w3wp占用CPU过高的解决过程(Dictionary和线程安全)、EntityFramework中的线程安全,又是Dictionary。
首先请大家不要喷我,因为这一次还是关于Dictionary的一些低级错误,我自己看到都无语了。。。
抓取Dump
使用任务管理器抓取Dump,如果操作系统较低可以使用“Process Explorer”。

使用WinDbg分析
1.使用WinDbg打开dump文件。
2.加载sos.dll
命令:.loadby sos clr

3.查看相关线程信息
命令:!threads –special
special参数会将由CLR创建的特殊线程单独列出便于减少线程的排查工作。

红框圈出的是我们要重点排查的线程(工作者线程),至于其它的则是一些CLR自拥有的一些线程,如:GC线程、对象释放线程、计时器线程、I/O线程等。
线程类型的名称翻译:
- GC:垃圾回收线程
- Finalizer:对象释放线程,.Net至少有一个,用于专门处理对象释放。
- Timer:计时器线程
- ThreadpoolWorker:工作者线程
- IOCompletion:I/O线程
4.查看具体线程堆栈
命令:~{ThreadId}s、!clrstack
~{ThreadId}s:将当前上下文切换到指定的线程内

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

第二个红框的前两句太长了,我复制在下面:
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等线程进行了查看,都是在这里堵塞了,那么问题浮出水面了,下面就去看代码,并且解决它。
解决问题
找到对应的代码:

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

解决方式很简单,使用了.NET4提供的线程安全的字典:ConcurrentDictionary。
关于这一次问题的思考
Dictionary为什么这么容易堵塞
这边引用之前的博文内容:
我知道Dictionary不是一个线程安全的类型,但我原本以为Dictionary在非线程安全方式下访问时数据会错乱,而不会堵塞或者死锁,而这次的这个问题让我感觉到讶异,为什么Add一个项目会造成堵塞?
反编译Dictionary的源码后发现异常的复杂,也没有细究,所以下面的一段描述大家抱有自己的想法去阅读,可能是错的也可能是对的。
![]()
![]()
上面是我认为存在问题的地方,当一个线程执行过Initialize后buckets数组的值被修改,而第二个线程同时进入了Initialize方法,那么第一个线程所维护的值被破坏,造成在算法环节出现了死循环,这也可以说明了为什么cpu有时候是50%有时候是99%的问题。
当前有多少个线程发生了这种状态,如果发生这种状态的线程越多则代表cpu占用越多。
这次问题的经验:以后在使用集合或字典时首先应该先想到System.Collections.Concurrent命名空间,虽然它的性能在正常情况下低于普通的Dictionary,但那么几十或者几百毫秒的损失对于稳定性来说微不足道,也减少了问题的发生。
写在最后
因为Rabbit.WeiXin是一个开源项目当然第一件事情就是发布更新。。避免更多的人出现此问题。

交流方式
QQ群:384413261(RabbitHub)
Email:majian159@live.com
再记一次w3wp占用CPU过高的解决过程(Dictionary和线程安全)的更多相关文章
- 记一次w3wp占用CPU过高的解决过程(Dictionary和线程安全)
项目上线以来一直存在一个比较揪心的问题,和一个没有信心处理的BUG,那就是在应用程序启动时有可能会导致cpu跑满99%或持续在一个值如50%左右,这样一来对服务器的压力是非常大的,经常出现服务器无法远 ...
- w3wp占用CPU过高
w3wp占用CPU过高 在此之前项目有发生过两次类似的状况,都得以解决,但最近又会发现偶尔CPU会跑满,虽然之前使用过WinDbg解决过两次问题但人的记忆是不可靠的,今天处理同样问题的时候还是遇到了一 ...
- memcache占用CPU过高的解决办法
Simon最近为公司服务器操碎了心 , 先是mysqld进程占用CPU过高 , 导致服务器性能变低 ,网站打开太慢.通过增加max_connections及table_cache解决了问题 ,随后发现 ...
- Linux排查Java程序占用CPU很高的解决办法
Java的工具集相当强大,学习成本也很低,处理线上问题时,jstack这个工具就比微软的windbg,好学好用很多,3步找出占用CPU很高的源所在.而windbg反人类的各种命令,实在不敢恭维. 故意 ...
- SQL Server 占用CPU较高的解决方法
触发原因:月底系统结账的时候对ERP的操作较多,有用户反馈系统之间的数据传输很久没有同步.随即到服务器上查看,没有发现有程序导致的问题,看了一下CPU的使用率,发现SQL Server占用率在百分之九 ...
- shopex-百度爬虫抓取过于频繁导致php-cgi占用CPU过高的解决办法
步骤 1.开启slowlog:php-fpm里修改配置 观察slowlog里的超时文件,然后修改相应超时文件 2.1修改完后,仍然无效,查看access.log,发现大量如下的请求 220.181.1 ...
- 记一次Mysql占用内存过高的优化过程
一.环境说明: 操作系统:CentOS 6.5 x86_64 数据库:Mysql 5.6.22 服务器:阿里云VPS,32G Mem,0 swap 二.问题情况: 1.某日发现公司线上系统的Mysql ...
- MySQL占用CPU超过百分之100解决过程
本文转载自: https://www.93bok.com 访问网页504 Gateway Time-out,登陆服务器查看,内存正常,CPU使用率达到了400%,因为是4核,所以到了400%,几乎全部 ...
- w3wp.exe占用cpu特别高
w3wp.exe占用cpu特别高,百度了一下在任务管理器标记出PID可以看到进程号. 试了一下,发现一个xxx网站占用cpu特别高,然后就结束了下进程,再重启网站cpu一下子降下来. 很奇怪,还需要具 ...
随机推荐
- c# UpdateLayeredWindow异形窗口
#region UpdateLayeredWindow #region 重写窗体的 CreateParams 属性 protected override CreateParams CreatePara ...
- LeetCode#227.Basic Calculator II
题目 Implement a basic calculator to evaluate a simple expression string. The expression string contai ...
- X264库直接压缩BITMAP格式数据
最近帮朋友看了下X264压缩视频,主要参考了雷霄骅(leixiaohua1020)的专栏的开源代码: http://blog.csdn.net/leixiaohua1020/article/detai ...
- get_free_page
/** 0.11用了 unsigned char */static unsigned short mem_map [ PAGING_PAGES ] = {0,}; /* * Get physical ...
- setTimeout()与setInterval()——走马灯效果
JavaScript中的setTimeout()与setInterval()都是指延时执行某一操作. 但setInterval()指每隔指定时间执行某操作,会循环不断地执行该操作:setTimeout ...
- LINUX下NFS系统的安装配置
准备:NFS系统服务器IP 192.168.135.1 ,NFS共享目录/mnt/NFS 一.安装NFS 查看nfs是否安装 #rpm -qa | grep nfs 若没有则安装nfs包 #yum i ...
- Device ehth0 is not present
context: 使用virtualbox 克隆了一个新硬盘,然后配为新建虚机的使用,但ifconfig只能发现lo,没有eth0 解决方案: 当前系统是centos6.6 cd /etc/udev/ ...
- 安装rpm包
下载好一个rpm包怎样安装? [root@localhost ~]# ls anaconda-ks.cfg install.log install.log.syslog jboss-as-7.1.1- ...
- css3中变形与动画(一)
css3制作动画的几个属性:变形(transform),过渡(transition)和动画(animation). 首先介绍transform变形. transform英文意思:改变,变形. css3 ...
- python中strip,lstrip,rstrip简介
一.起因 今天在做角色控制中,有一个地方用到rstrip,判断用户请求的url是否与数据库对应可用权限中url相符. if request.path == x.url or request.path. ...