.NET 8服务在Ubuntu下执行GC.WaitForPendingFinalizers时挂死排查求助
排查Ubuntu上.NET 8应用GC.WaitForPendingFinalizers挂死问题
先解决挂死时的转储收集问题
正常运行时能收集dump但挂死时不行,说明进程已进入无法响应诊断请求的状态,可通过gdb强制生成core dump:
- 执行
gdb -p <挂死进程PID>进入调试会话 - 在gdb提示符输入
generate-core-file,生成名为core.<PID>的core文件 - 退出gdb后,用
dotnet-dump analyze core.<PID>加载转储进行分析
定位Finalizer线程的阻塞点
进入dotnet-dump分析会话后,重点排查Finalizer线程状态:
- 执行
threads命令列出所有线程,找到名称包含Finalizer的线程(通常ID为2) - 切换到该线程:
set thread <Finalizer线程ID> - 执行
clrstack查看托管调用栈,执行native stack查看原生调用栈,确认它卡在哪个方法或原生代码段
针对Sqlite相关的定向排查
你的shutdown流程先清理了Sqlite连接池,结合Linux环境特性,重点排查:
- 临时注释
SqliteConnection.ClearAllPools();,重新测试shutdown,看挂死是否消失,缩小问题范围 - 检查使用的Sqlite NuGet包版本,确认是否存在Linux环境下Finalizer阻塞的已知问题
- 排查代码中是否有未正确Dispose的Sqlite对象(比如连接、命令),这类对象会进入Finalizer队列,若原生资源清理时遇到Linux特有的文件锁、IO阻塞,就会导致Finalizer线程挂起
启用诊断日志跟踪GC与Finalizer行为
给应用添加以下环境变量,重启后复现挂死,通过日志定位问题:
COMPlus_DebugWriteToStdErr=1:将诊断日志输出到标准错误流COMPlus_GCVerbose=1:生成详细GC日志,包含Finalizer队列处理情况COMPlus_TraceFinalizer=1:跟踪Finalizer线程的执行步骤,输出每个待终结对象的处理状态
排查线程死锁或资源竞争
在dotnet-dump分析会话中:
- 执行
syncblk命令查看同步块信息,检查是否有线程持有独占锁未释放 - 遍历所有线程的调用栈(
clrstack),看是否存在多个线程等待同一资源的情况,尤其是Finalizer线程是否在等待其他线程持有的锁
内容的提问来源于stack exchange,提问作者Vikram
相关产品推荐
相关产品推荐

