NET5 Windows服务停止后陷入已暂停状态无法终止的排查问题
问题诊断与定位方案
内核态层面排查(针对无法强制终止的核心特征)
taskkill /F 杀不掉的进程故障必然涉及内核态资源持有,优先做内核栈分析:
- 安装Windows SDK自带的Debugging Tools for Windows,无需重启服务器即可运行
- 以管理员权限启动Windbg x64,选择附件到目标幽灵进程
- 执行命令
!process 0 0获取目标进程的EPROCESS内核地址,再执行!process <EPROCESS地址> 7输出进程所有线程的内核调用栈 - 重点排查调用栈是否卡在第三方安全驱动(杀毒、EDR、主机审计类产品的网络过滤驱动)、Windows TCP/IP协议栈驱动的回调逻辑上,这类场景都是内核态IO请求块(IRP)泄漏导致进程引用计数无法清零,被系统标记为挂起状态
用户态.NET运行时层面排查
- 可复现场景下,给服务进程添加启动环境变量
COMPlus_ThreadPool_EnableWorkerTracking=1、COMPlus_Async_EnableAsyncLocalTracking=1开启异步任务跟踪 - 用.NET官方自带诊断工具
dotnet-dump collect -p <PID>抓取进程转储,执行dotnet-dump analyze分析转储文件 - 执行
dumpasync命令查看所有未完成的异步操作栈,确认是否存在大量未释放的Socket实例、SocketAsyncEventArgs对象、未完成的网络IO任务,检查CancellationToken传递是否覆盖所有底层异步调用 - 统计System.Net.Socket相关对象的引用计数,确认是否存在非托管句柄泄漏
第三方软件干扰验证
- 找同配置的空闲生产服务器,卸载所有第三方安全、审计类软件,模拟生产高负载压测,观察服务退出后是否仍出现幽灵进程,排除内核驱动挂钩导致的逻辑阻塞
匹配根因与修复方案
- .NET5存在Windows服务异步退出的已知Bug:高并发场景下Host停止时,若异步IO完成端口回调在进程退出流程中触发,会导致运行时无法正确释放所有内核句柄,进程引用计数泄漏,该问题在.NET6及以上LTS版本中已修复,优先建议升级到.NET6或.NET8,90%以上同类型问题升级后直接解决
- 暂时无法升级大版本的场景下,可在IHostApplicationLifetime的ApplicationStopping事件中添加强制退出逻辑:等待3秒后直接调用
Environment.Exit(1)终止进程,跳过Host默认的异步任务等待逻辑,避免高并发下触发资源泄漏 - 所有异步网络操作的CancellationToken注册回调中,手动调用Socket.Dispose()释放句柄,不要仅依赖CancellationToken取消异步任务,从用户态主动触发内核IO资源释放
内容的提问来源于stack exchange,提问作者Dunge
相关产品推荐
相关产品推荐

