2013-09-06 5 views
8

多数の同時接続がアクティブになると、急速に機能低下する傾向のある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 

答えて

1

のZooKeeperクライアントが所有する項目を示している(問題となっていますさもなければ、私は多くのF#ユーザーがこの問題にヒットしたと思う)。コールスタックからは、あなたのコードがクリティカルセクションで待機しているように見えますが、これは問題の原因となる可能性がより高いようです...コードが依存している可能性のある同期プリミティブは何ですか?

+0

私はロックを使用しているので、標準の.Net Monitorクラスですが、これらが表示されているスタックトレースはありませんそのコードの近く。これは基本的にリスト処理(List.iter、Map.findなど)です。興味深いのは、すべてのスレッドが多かれ少なかれ同じアクションを実行していますが、アクティブな接続である60人ほどのうち、6つだけがプリエンプティブGCを無効にしていることです。 – ckramer

+1

'List.iter(fun _ - >。 。lock ..)xs'はスタックトレースによって 'List.iter'に参照されます。 – t0yv0

+0

プリエンプティブGCを無効にしているトレースにはロックがありません。それらはまた、異なるテール最適化関数で発生しています(あるケースではMapTreeInternal.mapi、もう1つはPrimitives.Basics.List.iter、もう1つはMapTreeModule.findにあります)。これらの呼び出しはすべてF#レコードタイプでも働いています。したがって、管理対象外のリソースはもちろんのこと、ここにはディスポーザブルインスタンスも存在しないことがわかります。すべてのスレッドが共通に持つことの1つは、非同期TCP受信操作を介して呼び出されることです。私はそれが何らかの形で関わっているのかどうかわからない。 – ckramer

1

おそらく少し遅れていますが、あなたが記述している問題は、私が持っていたものとは少し違って見えますが、あなたが与えたコールトレースは、共通点があるかもしれないことを示唆しています。

my answerで詳細を見つけることができますが、要するにWindows 7と.NET 4.0-4.5の組み合わせになって、F#でテール再帰が発生し、過剰なロックが発生します。 .NETから4.6へのアップデート、またはWindows 8へのアップグレードは、この問題を解決します。

また、ガベージコレクションに問題があるため、server garbage collectionを使用してみるとよいでしょう。これは私が上記の問題を見つける前にしたことの一つであり、私たちが経験していたパフォーマンスの問題の大部分を解決しました。あなたのapp.configには、次のものが必要です:

<configuration> 
    ... 
    <runtime> 
    ... 
    <gcServer enabled="true"/> 
    ... 
    </runtime> 
    ... 
</configuration> 
関連する問題