zoukankan      html  css  js  c++  java
  • Windbg程序调试系列3-线程阻塞问题

    上一篇博文给大家分享了使用Windbg分析内存泄露问题:

    Windbg程序调试系列2-内存泄露问题

    本篇我们继续跟大家分享,如何分析解决线程阻塞问题。

    从根本上讲,线程阻塞属于程序Hang的一种,其表现主要有:

    1. 随着请求的增加,线程数一直增加,可能会把线程池打爆

    2. 低CPU使用率(被阻塞后的CPU使用率降低)

    3. 请求没有返回,客户端一直在等待,直至Timeout。

     那么,从线程状态上看,什么是阻塞? 一个线程经历的5个状态,创建,就绪,运行,阻塞,终止。各个状态的转换条件如下图:

    上图中有个阻塞状态,就是说当线程中调用某个函数,需要IO请求,或者暂时得不到竞争资源的,操作系统会把该线程阻塞起来,避免浪费CPU资源,等到得到了资源,再变成就绪状态,等待CPU调度运行。

    线程发生阻塞的现象就是,进程的线程数会越来越多!

    线程阻塞问题的分析思路:

    持续请求过程中,抓两个或者三个Dump,看线程增加的速度,每次抓Dump间隔30s或者1分钟
    对比的看每个Dump中:

    1. 线程池的大小 !threadpool
    2. 线程的分类和状态 !threads
    3. 查看线程阻塞 !syncblk
    4. 查看阻塞线程的根源线程、线程请求的资源对象 、被阻塞的线程数
    5. 查看阻塞根源线程的堆栈~Xs !clrstack
    6. 分析线程阻塞的原因,改进代码

    1. 查看线程池的大小:!threadpool,有时间间隔两个Dump对比着看,看线程池的线程数的增长情况:

    2. 查看线程的分类和线程的状态 !threads,从下图可以看出,后台线程一直在增加

    3. 查看线程阻塞  !syncblk,也是看这两个dump,对比着看

    我们发现:

    第一个Dump中95号线程 阻塞了(1021-1)/2=510个线程
    第二个Dump中79号线程 阻塞了(1099-1)/2=549个线程

    95号线程独占的对象资源 00000026ba7c4dc0 (System.Object)

    79号线程独占的对象资源也是00000026ba7c4dc0(System.Object)

    两个线程同时锁住了同一个资源!00000026ba7c4dc0(System.Object)

    此时,线程阻塞问题已经确定,接下来,我们要重点分析阻塞的根源线程(持有什么资源不释放,导致其他线程在等待),95号线程、79号线程

    4. 查看阻塞线程的根源线程、线程请求的资源对象 、被阻塞的线程数

    例如 95号线程:

    1 查看阻塞根源线程的堆栈
    2 ~95s  
    3 !clrstack

    通过线程堆栈,我们在栈顶发现,95号线程,在等待Socket Server返回,具体再等哪个Socket Server?

    通过以下命令找出当前线程堆栈上的Socket对象

    !dso

    这样我们就定位出95号线程在做什么,在等待什么:

    95号线程在等待SocketServer 10.*.*.*:80返回数据,独占资源:00000026ba7c4dc0(System.Object)

    同时我们通过线程堆栈看到了我们自己的一个TCP通讯类TCPInvoker, 在创建一个新的TCP连接,TCPInvoker类的代码需要重点关注,继续看!

    我们继续看79号线程:

    1 ~79s  
    2  !clrstack

    通过79号线程的堆栈和阻塞情况可以发现:

    79号线程Monitor.Enter(object),在请求资源的独占锁:00000026ba7c4dc0(System.Object)

    TCPInvoker卡在了GetInvoker方法上。我们需要看看TCPInvoker的代码了

    5. 分析线程阻塞的原因,改进代码

    从如下的代码中,我们能看到:

    95号线程是执行到了GetInvoker方法的Create,Create中在等待Socket Server返回,此时如果Socket Server没有响应,超时时间默认是5s,会一直持有资源00000026ba7c4dc0(System.Object)不释放

    79号线程也执行到了GetInvoker方法,但是在Lock时,等待95号线程释放资源:00000026ba7c4dc0(System.Object)

    随着请求越来越多,超时+重试连接Socket Server,导致线程阻塞住了。

    解决方案:1. 分析Socket Server为什么连不上 2. 优化改进TCPInvoker内部的业务逻辑,减少超时和重试时间,减少阻塞的产生几率。

    好了,上面就是这次分享的Windbg调试线程阻塞问题的细节和过程,总结一下:

    线程阻塞问题的分析思路:

    1. 线程池的大小 !threadpool
    2. 线程的分类和状态 !threads
    3. 查看线程阻塞 !syncblk
    4. 查看阻塞线程的根源线程、线程请求的资源对象 、被阻塞的线程数
    5. 查看阻塞根源线程的堆栈~Xs !clrstack
    6. 分析线程阻塞的原因,改进代码

    周国庆

    2018/11/1

  • 相关阅读:
    Write an algorithm such that if an element in an MxN matrix is 0, its entire row and column is set to 0.
    旋转二维数组
    replace empty char with new string,unsafe method和native implementation的性能比较
    判断一字符串是否可以另一字符串重新排列而成
    移除重复字符的几个算法简单比较
    也来纠结一下字符串翻转
    判断重复字符存在:更有意义一点
    程序员常去网站汇总
    sublime
    针对程序集 'SqlServerTime' 的 ALTER ASSEMBLY 失败,因为程序集 'SqlServerTime' 未获授权(PERMISSION_SET = EXTERNAL_ACCESS)
  • 原文地址:https://www.cnblogs.com/tianqing/p/9887309.html
Copyright © 2011-2022 走看看