14

我們的應用程序使用託管(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 
+0

您可以使用Debug Diag來分析轉儲,因爲它可以分析比sosex更多的死鎖模式。但是,沒有自動工具可以識別所有模式,因爲即使是人類,死鎖有時也太複雜,難以理解。如果您負擔得起,請通過http://support.microsoft.com打開支持案例以諮詢Microsoft。 – 2012-02-15 08:40:57

+0

@LexLi,感謝您的調試診斷建議。我之前遇到過它,但因爲它看起來太IIS特定而被駁回。我將它運行在前面的一個mem dump上,它基本上指出了同樣的事情 - GC線程正在等待另一個線程擁有的crit sec。哪種讓我對僵局有所確認。看來Debug Diag使用相同的psscor4擴展。我們也在研究MS支持選項。謝謝! – user1210698 2012-02-15 10:01:19

+0

我想你應該檢查所有的終結器實現(〜)。看起來你已經在終結器中陷入僵局 – 6opuc 2012-05-06 18:37:02

回答

2

此行的第二調用堆棧看起來可疑:

000000001fc5df50 000007fef95dbb4e clr! ?? ::FNODOBFM::`string'+0x9fcc4 

看的偏移地址是多麼大,我沒有看到任何模塊名稱 - 你丟失了一些符號?

也許在該庫中有一個終結器會導致問題。

+0

雖然該方法看起來像是CLR的一部分,但我不確定這些符號。 – user1210698 2012-05-12 05:55:12

+0

雖然該方法看起來像是CLR的一部分,但我並不確定這些符號。也不使用任何COM,只是C#和託管的C++程序集。無論如何,我們最終做了一些改變,例如用超時將一些鎖定語句改爲Monitor.Enter,在分配很多小對象的邏輯中添加了一個GC.Collect。最後幾個月我們沒有看到這個問題。 – user1210698 2012-05-12 06:00:53

+0

通常,一個很大的偏移量:+ 0x9fcc4意味着列表中的堆棧幀只是調試器可以找到的最後一個位置,然後大偏移量顯示爲最後一個已知點與當前執行點之間的差異真的是。然而,我搜索了「FNODOBFM」,並發現這個:http://bit.ly/KTLcZh和這個:http://bit.ly/J5HqPJ(有點不要溢出最大字符爲這個評論)。我認爲這條線可能是由於優化器的重新排列 - 使得很難知道真正的堆棧。也許這些文章可以幫助。 – JMarsch 2012-05-13 01:08:48

0

我不是一個大的專家,但只是好奇,想知道是否在鎖定一些資源時終結器線程崩潰了(我的意思是終結器線程中未處理的異常),並且GC線程正試圖獲取該線程?