码迷,mamicode.com
首页 > 其他好文 > 详细

w3wp占用CPU过高

时间:2015-11-13 23:37:22      阅读:296      评论:0      收藏:0      [点我收藏+]

标签:

w3wp占用CPU过高

在此之前项目有发生过两次类似的状况,都得以解决,但最近又会发现偶尔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过高

标签:

原文地址:http://www.cnblogs.com/Leo_wl/p/4963503.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!