• Dictionary CPU 100%


      昨天服务器的CPU突然100%,此服务已经运行几年了,都平安无事。既然问题出现当然要找出这个遗留多年的小概率问题。出现cpu 100% 一般就是哪里出现了无法跳出的死循环。

      1、获取进程的内存信息

      服务器使用的window server 直接右键创建转储文件即可。这个直接点点的方式是使用window server最方便的地方(^_^)。

      2、加载内存文件信息

      将文件复制本地,直接拖拽到windbg中。(windbg直接在window 应用商店下载即可)

      

      3、获取进程内耗时线程

      在0:000 输入框中输入!runaway 敲回车,获取线程占用cpu时间

      

       

       4、获取线程的栈信息

      从cpu的线程占用时间来看,线程64,89,96,95,90占用的时间最长,可以初步断定问题就出现在这几个线程中。输入:~64s进入该线程(64代表的是线程id)

      

      进入该线程后就可以加载线程的栈信息了,在命令框中输入!CLRStack 。如果出现图示信息说明需要单独加载SOS.dll 文件。使用everything软件全局搜索该dll文件位置,然后在输入框中:.load 全路径SOS.dll。加载完成再次输入:!CLRStack 就可以正常显示栈信息了。

      

      5、问题定位

      从栈信息来看,线程一直停留在:System.Collections.Generic.Dictionary`2[[System.__Canon, mscorlib],[System.__Canon, mscorlib]].FindEntry(System.__Canon)这个方法里面,调用这个方法的类是:Aop.Api.Parser.AopJsonParser,这个类是支付宝官方sdk中的。先看FindEntry这个方法干了啥。直接官网查看源码:

      

    private int FindEntry(TKey key) {
                if( key == null) {
                    ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key);
                }
     
                if (buckets != null) {
                    int hashCode = comparer.GetHashCode(key) & 0x7FFFFFFF;
                    for (int i = buckets[hashCode % buckets.Length]; i >= 0; i = entries[i].next) {
                        if (entries[i].hashCode == hashCode && comparer.Equals(entries[i].key, key)) return i;
                    }
                }
                return -1;
            }

      从源码来就是判断key是否存在,看来就是死循环for里面了。再来看这个dictionary是用来干啥了的,反编译Aop dll文件

    private static Dictionary<string, AopAttribute> GetAopAttributes(Type type)
    {
        Dictionary<string, AopAttribute> dictionary = null;
        if (!AopJsonParser<T>.attrs.TryGetValue(type.FullName, out dictionary) || (dictionary == null))
        {
            dictionary = new Dictionary<string, AopAttribute>();
    private static readonly Dictionary<string, Dictionary<string, AopAttribute>> attrs;
     
    
     

      从源码可以看见定义了一个静态Dictionary attrs变量,既然是静态变量,会出现多线程竞争问题。官网也明确说明Dictionary 是非线程安全的,如果多线程读写需要自己去写程序保证线程安全或者使用ConcurrentDictionary。

      6、问题

      问题的根本原因是多线程多写非线程安全Dictionary,导致在FindEntry方法死循环。

      

  • 相关阅读:
    心理学安全威胁
    设计模式是在运用构造定律
    分形理论
    构造定律
    [SOA]REST与SOA两种架构的异同比较
    加法是自然之道
    ES : 软件工程学的复杂度理论及物理学解释
    软件架构的灵活设计
    软件复杂度与结构:(影响复杂度的因素)
    socket 的通信过程
  • 原文地址:https://www.cnblogs.com/gsjlovenet/p/10692927.html
Copyright © 2020-2023  润新知