最近我们发现我们的一个服务器应用程序(所以它是 Windows 服务)因 OutOfMemory 异常而失败。我们试图找出发生了什么,最终我们发现 finalize 队列中的对象没有被最终确定,因此不会对它们进行垃圾收集。我们试图找出哪个终结器可以通过使用 Windbg 导致此行为,但我们无法找出究竟是哪个对象导致它。
通过使用 !finalizequeue 命令,我们可以发现:
0:053> !finalizequeue 未加载 clr.dll 的 PDB 符号 要清理的同步块:0 要发布的自由线程接口:0 待发布的 MTA 接口:0 即将发布的STA接口:0 ---------------------------------- 第 0 代有 28 个可终结对象 (050eab4c->050eabbc) 第 1 代有 15 个可终结对象 (050eab10->050eab4c) 第 2 代有 658 个可终结对象 (050ea0c8->050eab10) 准备完成 3027 个对象 (050eabbc->050edb08) ...
3027 是一个非常高的数字(在运行几分钟后,这个数字仍在增长并且从未下降)。我试图找出地址 050eabbc 上的对象,但它总是不同的类型,所以我认为这不是原因。
如果我尝试打印终结器线程的本机调用堆栈,我得到了这个:
0:053>~2k *** 错误:找不到符号文件。默认为 C:\Windows\SYSTEM32\KERNELBASE.dll 导出符号 - ChildEBP RetAddr 警告:堆栈展开信息不可用。以下框架可能是错误的。 032ef09c 772f10b4 ntdll!ZwWaitForSingleObject+0xc *** 错误:找不到符号文件。默认为 C:\Windows\SYSTEM32\combase.dll 导出符号 - 032ef0b0 755ff0b5 内核基础!等待单个对象+0x12 032ef0e4 7554b22a 组合!NdrOleDllGetClassObject+0x1399 032ef108 755ff10c 组合!PropVariantCopy+0x177b 032ef224 75511724 combase!NdrOleDllGetClassObject+0x13f0 032ef27c 7558115d combase!DcomChannelSetHResult+0x17c7 032ef2d8 755fd39a combase!CoRegisterSurrogateEx+0x3494 *** 错误:找不到符号文件。默认为 C:\Windows\SYSTEM32\RPCRT4.dll 导出符号 - 032ef2f4 76a9e4a0 组合!NdrExtStubInitialize+0x21a9 032ef71c 755fc779 RPCRT4!NdrComplexArrayUnmarshall+0xcac 032ef738 75510d77 组合!NdrExtStubInitialize+0x1588 032ef748 755816d5 combase!DcomChannelSetHResult+0xe1a 032ef7dc 75587aa5 combase!CoRegisterSurrogateEx+0x3a0c *** 错误:找不到符号文件。默认为 C:\Windows\Microsoft.NET\Framework\v4.0.30319\clr.dll 导出符号 - 032ef82c 748ab680 组合!StringFromIID+0x28d 032ef92c 748ab758 clr!PreBindAssemblyEx+0x259d 032ef964 7487960d clr!PreBindAssemblyEx+0x2675 032ef980 748ab55a clr!GetMetaDataInternalInterfaceFromPublic+0x2162a 032ef9dc 74878915 clr!PreBindAssemblyEx+0x2477 032efa2c 7487887c clr!GetMetaDataInternalInterfaceFromPublic+0x20932 032efa44 7478a5e2 clr!GetMetaDataInternalInterfaceFromPublic+0x20899 032efa8c 74777d71 clr!GetPrivateContextsPerfCounters+0x968
终结器线程总是卡在 ZwWaitForSingleObject 上,所以这是终结器线程卡住的另一个线索。
所以我的问题是,如何找出导致终结器队列卡住的对象?有趣的是我根本不使用终结器:-(