windbg 分析线程死锁

📅 2026/7/11 23:23:50
windbg 分析线程死锁
一、第一步宏观看整体指标 !tp查看线程池Worker总数、Running/Idle、排队队列特征Running总线程、Idle0、队列积压几千 → 大批量线程永久卡死不释放。初步结论不是瞬时并发高是线程泄漏卡死。回到顶部二、第二步排查托管锁 !syncblk看每条MonitorHeld占用数、有无等待的Waiter线程① 有大量等待线程 多lock互相争抢传统Monitor死锁② 只有占用、无等待线程 线程拿着锁卡在业务代码锁是副产品不是元凶你的场景回到顶部三、第三步抽卡死线程栈从syncblk里提取OS-TID~~[0xTID]s;!clrstack 打印单个卡死线程托管堆栈栈出现ManualResetEventSlim.Wait → Task.InternalWait → Task.Wait()→ 锁定同步.Wait()阻塞异步任务上下文死锁。向上追溯业务类定位出事方法ServiceDiscovery、MatrixHelper、HttpModule、Controller。回到顶部四、第四步结合代码解释「偶发正常、随机卡死」命中缓存/连接复用GetAsync同步执行完毕返回已完成Taskawait不放线程全链路顺行正常释放真实跨网IO返回未完成Taskawait释放工作线程IO完成回调要切回AspNetSynchronizationContext但主线程被.Wait()占死 → 闭环死锁、线程永久滞留。回到顶部五、第五步区分两种死锁、落地修复传统lock死锁A拿锁1等锁2、B拿锁2等锁1 → 改锁顺序、缩小lock范围ASP上下文死锁(本次故障)同步.Wait()/Result await无ConfigureAwait(false)修复二选一方案1全链路改成async/await删除所有.Wait()方案2所有await xxx.ConfigureAwait(false)切断回调绑定请求上下文。