多数の同時接続がアクティブになると、急速に機能低下する傾向のあるWindowsサービスで本番の問題をデバッグしようとしています。コアダンプとDebugDiagの魔法を使って、保留中のGC操作があり、Preemptive GCを無効にしたいくつかのスレッドが作業を完了するまで開始できないことがわかりました。ここでCLR .tail命令はプリエンプティブGCを無効にしますか?
は、問題のあるスレッドを示すのWinDbgからサンプルスレッドダンプです:
26 6e 1444 00..440 8009222 Disabled 00..200:00..f88 00..7a0 0 MTA (Threadpool Completion Port)
27 c1 1a0c 00..fe0 8009222 Disabled 00..e90:00..f88 00..7a0 0 MTA (Threadpool Completion Port)
28 b5 17bc 00..6f0 8009222 Disabled 00..268:00..f88 00..7a0 0 MTA (Threadpool Completion Port)
29 89 1f1c 00..ab0 8009222 Disabled 00..a30:00..f88 00..7a0 0 MTA (Threadpool Completion Port)
30 ac 2340 00..f70 8009220 Disabled 00..d00:00..d08 00..7a0 1 MTA (GC) (Threadpool Completion Port)
31 88 1b64 00..fd0 8009220 Enabled 00..b28:00..b48 00..7a0 0 MTA (Threadpool Completion Port)
だからここにあなたが先制GC無効(スレッド26,27,28,29)と1(スレッドを持っているいくつかのスレッドを見ることができますこれらのスレッドでGCを実行するために待機しています。
私のGoogle-fuは、類似の問題のようなものを記述するthis blog postに私を導いています。私のケースではXMLは関係ありませんでした。これは、しかし掘る場所を知っている私に十分な情報を与え、そして最終的に私は無効になってプリエンプティブGCとスレッドの共通の特徴の一つは、上部に、このように見えたスタックトレースであることを発見した:
ntdll!NtWaitForSingleObject+a
ntdll!RtlpWaitOnCriticalSection+e8
ntdll!RtlEnterCriticalSection+d1
ntdll!RtlpLookupDynamicFunctionEntry+58
ntdll!RtlLookupFunctionEntry+a3
clr!JIT_TailCall+db
...
DebugDiagもクリティカルセクションについて私に警告し、それがちょうどそうJIT_TailCall
とのスレッドもRtlEnterCriticalSection
で唯一のスレッドであることを起こるので、私の質問は:は、それが実際には、このデッドロックを引き起こしている.tail
命令ですか?もしそうなら:私はそれについて何ができますか?
私は私の.fsprojファイルにtailcallsを無効にすることができますが、これらの少なくとも一方がFSharp.Core.dll
から来ていると逆コンパイラでのいくつかの洞窟探検は.tail
命令の存在を確認するようだように見えます。だから私は、プロジェクトの設定を変更すると.tail
命令がすべて削除されることはわかりません。
これまで誰かがこのようなことをしたことがありますか?
更新: さらに役立つ情報です。ここで
このダンプの!locks
の出力されます。
!locks
CritSec +401680 at 0000000000401680
WaiterWoken No
LockCount 0
RecursionCount 1
OwningThread 2340
EntryCount 0
ContentionCount bf
*** Locked
Scanned 1657 critical sections
スレッド2340は、GC(私は上記の含まれる部分リスト内のスレッド30)を開始したスレッドです。
そして!syncblk
は唯一私がtailcallsを疑う(これは、迷惑ながら、開始からGCを維持しているスタックのいずれかに関与していない)
!syncblk
Index SyncBlock MonitorHeld Recursion Owning Thread Info SyncBlock Owner
11 0000000019721a38 1 1 0000000019766e20 638 7 0000000000fb2950 System.Collections.Generic.LinkedList`1[[ZooKeeperNet.Packet, ZooKeeperNet]]
Waiting threads:
18 0000000019721c68 1 1 000000001ae71420 8ac 13 00000000012defc8 System.Collections.Generic.LinkedList`1[[ZooKeeperNet.Packet, ZooKeeperNet]]
Waiting threads:
-----------------------------
Total 64
CCW 0
RCW 0
ComClassFactory 0
Free 5
私はロックを使用しているので、標準の.Net Monitorクラスですが、これらが表示されているスタックトレースはありませんそのコードの近く。これは基本的にリスト処理(List.iter、Map.findなど)です。興味深いのは、すべてのスレッドが多かれ少なかれ同じアクションを実行していますが、アクティブな接続である60人ほどのうち、6つだけがプリエンプティブGCを無効にしていることです。 – ckramer
'List.iter(fun _ - >。 。lock ..)xs'はスタックトレースによって 'List.iter'に参照されます。 – t0yv0
プリエンプティブGCを無効にしているトレースにはロックがありません。それらはまた、異なるテール最適化関数で発生しています(あるケースではMapTreeInternal.mapi、もう1つはPrimitives.Basics.List.iter、もう1つはMapTreeModule.findにあります)。これらの呼び出しはすべてF#レコードタイプでも働いています。したがって、管理対象外のリソースはもちろんのこと、ここにはディスポーザブルインスタンスも存在しないことがわかります。すべてのスレッドが共通に持つことの1つは、非同期TCP受信操作を介して呼び出されることです。私はそれが何らかの形で関わっているのかどうかわからない。 – ckramer