我们的应用程序使用托管(C#)和非托管(C++)代码的混合存在问题。基本上我们有一个调用一堆程序集的exe,其中一个程序集是我们C++库的MC++包装器。该应用程序是一个控制台应用大多数情况下,它可以正常工作,但偶尔也会挂起而没有任何错误或异常。.NET应用程序挂起GC线程死锁
使用内存转储和符号,我们已经能够在WinDbg中做一些诊断,但我不确定我们看到的是一个死锁或不死锁。我搜索了堆栈中出现的CLR方法名称,但一直未能找到一个线程试图分配内存并使GC死锁的情况。
到目前为止,我已经尝试过与sos,sosex,psscor4扩展一起使用WinDbg。 Intrestingly sosex有一个命令来检查死锁(!dlk),但它报告没有死锁。
很难发布代码,因为它是一个庞大而复杂的应用程序。有.NET 3.5和4.0程序集的混合。托管代码和非托管代码中都有线程。
我会appricate是否有人可以看看堆栈跟踪并确认这是GC线程可能发生的死锁。或者,如果您可以使用C#和MC++的.NET应用程序中的其他方式来调试死锁/挂起,则更好。
这是我到目前为止有:
文章列表时,应用程序挂起:
ThreadCount: 8
UnstartedThread: 0
BackgroundThread: 5
PendingThread: 0
DeadThread: 0
Hosted Runtime: no
PreEmptive Lock
ID OSID ThreadOBJ State GC GC Alloc Context Domain Count APT Exception
0 1 de0 00000000008069f0 a020 Enabled 0000000000000000:0000000000000000 00000000007fa280 0 MTA
2 2 2130 000000000080bd30 b220 Enabled 0000000000000000:0000000000000000 00000000007fa280 0 MTA (Finalizer)
4 3 14fc 000000001d182880 200b020 Enabled 0000000000000000:0000000000000000 00000000007fa280 0 MTA
5 4 20d0 000000001d18b400 b220 Enabled 0000000000000000:0000000000000000 00000000007fa280 2 MTA (GC)
6 5 18a8 000000001d19f6a0 b020 Enabled 0000000000000000:0000000000000000 00000000007fa280 0 MTA
7 6 18a0 000000001d1c6f10 220 Enabled 0000000000000000:0000000000000000 00000000007fa280 0 Ukn
8 7 12f4 000000001d1c1ee0 220 Enabled 0000000000000000:0000000000000000 00000000007fa280 0 Ukn
10 8 2170 000000001d1c2ad0 220 Enabled 0000000000000000:0000000000000000 00000000007fa280 0 Ukn
OSID Special thread type
1 2570 DbgHelper
2 2130 Finalizer
5 20d0 SuspendEE
12 1890 GC
这就是GC线程的堆栈看起来像(线程!):
OS Thread Id: 0x1890 (12)
Child-SP RetAddr Call Site
0000000023e9f898 000000007799e4e8 ntdll!ZwWaitForSingleObject+0xa
0000000023e9f8a0 000000007799e3db ntdll!RtlpWaitOnCriticalSection+0xe8
0000000023e9f950 000007fef95d603e ntdll!RtlEnterCriticalSection+0xd1
0000000023e9f980 000007fef947bc41 clr!UnsafeEEEnterCriticalSection+0x1f
0000000023e9f9b0 000007fef947613a clr!CrstBase::Enter+0x1a1
0000000023e9f9f0 000007fef95da3a2 clr!ThreadStore::LockThreadStore+0x9a
0000000023e9fa20 000007fef9679675 clr!WKS::GCHeap::SuspendEE+0x82
0000000023e9fb20 000007fef9677eb2 clr!WKS::gc_heap::bgc_suspend_EE+0x25
0000000023e9fb50 000007fef98455b0 clr!WKS::gc_heap::background_mark_phase+0x236
0000000023e9fbb0 000007fef9677b76 clr! ?? ::FNODOBFM::`string'+0x9f85d
0000000023e9fc00 00000000773d652d clr!WKS::gc_heap::gc_thread_function+0xd3
0000000023e9fc30 000000007797c521 KERNEL32!BaseThreadInitThunk+0xd
0000000023e9fc60 0000000000000000 ntdll!RtlUserThreadStart+0x1d
对我来说,它看起来像GC线程正在等待关键部分。我们能够找到关键部分的地址,然后找到它的所有者线程(!critsec)。所有者线程的堆栈如下所示。我已经修剪它,以保持这篇文章的简短。 (!dumpstack)
OS Thread Id: 0x20d0 (5)
Child-SP RetAddr Call Site
000000001fc5dd38 000007fefe0510dc ntdll!ZwWaitForSingleObject+0xa
000000001fc5dd40 000007fef9478817 KERNELBASE!WaitForSingleObjectEx+0x79
000000001fc5dde0 000007fef94787c0 clr!CLREvent::WaitEx+0x170
000000001fc5de20 000007fef947866b clr!CLREvent::WaitEx+0xf8
000000001fc5de80 000007fef967a15b clr!CLREvent::WaitEx+0x5e
000000001fc5df20 000007fef967a001 clr!WKS::gc_heap::user_thread_wait+0x49
000000001fc5df50 000007fef95dbb4e clr! ?? ::FNODOBFM::`string'+0x9fcc4
000000001fc5e030 000007fef95da22e clr!WKS::GCHeap::GarbageCollectGeneration+0x14e
000000001fc5e080 000007fef95d9e4e clr!WKS::gc_heap::try_allocate_more_space+0x25f
000000001fc5e150 000007fef95d9fc8 clr!WKS::GCHeap::Alloc+0x7e
000000001fc5e180 000007fef947407c clr!AllocateArrayEx+0xa6b
000000001fc5e2f0 000007fef8555b75 clr!JIT_NewArr1+0x45c
000000001fc5e4c0 000007fef8561103 mscorlib_ni!System.Reflection.CustomAttributeData.GetCustomAttributeRecords(System.Reflection.RuntimeModule, Int32)+0x115
000000001fc5e590 000007fef855db55 mscorlib_ni!System.Reflection.CustomAttribute.IsCustomAttributeDefined(System.Reflection.RuntimeModule, Int32, System.RuntimeType, Boolean)+0x103
000000001fc5e720 000007fef856c8ac mscorlib_ni!System.Reflection.CustomAttribute.IsDefined(System.RuntimeType, System.RuntimeType, Boolean)+0x75
000000001fc5e770 000007fef857fe46 mscorlib_ni!System.Enum.InternalFormat(System.RuntimeType, System.Object)+0x2c
000000001fc5e7b0 000007fef8554f3b mscorlib_ni!System.Text.StringBuilder.AppendFormat(System.IFormatProvider, System.String, System.Object[])+0x2e6
000000001fc5e850 000007ff03c640fc mscorlib_ni!System.String.Format(System.IFormatProvider, System.String, System.Object[])+0x7b
000000001fc5e8b0 000007ff03c638a6 MyLibrary1!NumberCache.NumberEntry.ToString()+0x26c
您可以使用Debug Diag来分析转储,因为它可以分析比sosex更多的死锁模式。但是,没有自动工具可以识别所有模式,因为即使是人类,死锁有时也太复杂,难以理解。如果您负担得起,请通过http://support.microsoft.com打开支持案例以咨询Microsoft。 – 2012-02-15 08:40:57
@LexLi,感谢您的调试诊断建议。我之前遇到过它,但因为它看起来太IIS特定而被驳回。我将它运行在前面的一个mem dump上,它基本上指出了同样的事情 - GC线程正在等待另一个线程拥有的crit sec。哪种让我对僵局有所确认。看来Debug Diag使用相同的psscor4扩展。我们也在研究MS支持选项。谢谢! – user1210698 2012-02-15 10:01:19
我想你应该检查所有的终结器实现(〜)。看起来你已经在终结器中陷入僵局 – 6opuc 2012-05-06 18:37:02