8

TL;DR:サーバー GC 対応アプリケーションは、何十もの特別なGC スレッドを表示し、時間の経過とともにハングします。それを説明できるものは何ですか?


最近、.NET サービスで発生する奇妙なマルチスレッド/競合の問題に悩まされています。症状は次のとおりです。

  • プログラムが長時間 (数秒から数分) ハングする
  • スレッド数が異常に多い
  • プログラムが応答を停止したときに競合のピークがあります (次のグラフを参照)。
  • 同じプログラムが異なるサーバーにデプロイされ、一部のインスタンスにはまったく問題がありません (同じハードウェア/OS/CLR)

競合のピーク

私はすぐに、マネージ スレッド プールが膨大な数のスレッドを開始し、すべてのスレッドが 1 つまたは複数の共通リソースを共有しようとするコードの問題を疑っていました。ThreadPool の使用は非常に小さく、非常に制御されているように見えました。

すでに非常に多くのスレッド (通常の状態では約 20 になるはずのスレッドが 100 以上) を持っている、まだハングしていないサービスのダンプ ファイルを取得することができました。

windbg + sos を使用して、ThreadPool サイズが問題ないことを確認しました。

0:000> !threadpool
CPU utilization: 0%
Worker Thread: Total: 8 Running: 1 Idle: 7 MaxLimit: 32767 MinLimit: 32
Work Request in Queue: 0
--------------------------------------
Number of Timers: 1
--------------------------------------
Completion Port Thread:Total: 1 Free: 1 MaxFree: 64 CurrentLimit: 1 MaxLimit: 1000 MinLimit: 32

たった 8 つのワーカー スレッド... 次に、すべてのマネージド スレッド スタックを一覧表示したところ、認識できない多くのスレッドが見つかりました。一例として以下を参照してください。

0:000> !eestack
(...)
Thread  94
Current frame: ntdll!NtWaitForSingleObject+0xa
Child-SP         RetAddr          Caller, Callee
0000008e25b2f770 000007f8f5a210ea KERNELBASE!WaitForSingleObjectEx+0x92, calling ntdll!NtWaitForSingleObject
0000008e25b2f810 000007f8ece549bf clr!CLREventBase::WaitEx+0x16c, calling kernel32!WaitForSingleObjectEx
0000008e25b2f820 000007f8f5a2152c KERNELBASE!SetEvent+0xc, calling ntdll!NtSetEvent
0000008e25b2f850 000007f8ece54977 clr!CLREventBase::WaitEx+0x103, calling clr!CLREventBase::WaitEx+0x134
0000008e25b2f8b0 000007f8ece548f8 clr!CLREventBase::WaitEx+0x70, calling clr!CLREventBase::WaitEx+0xe4
0000008e25b2f8e0 000007f8ed06526d clr!SVR::gc_heap::gc1+0x323, calling clr!SVR::GCStatistics::Enabled
0000008e25b2f940 000007f8ecfbe0b3 clr!SVR::gc_heap::bgc_thread_function+0x83, calling clr!CLREventBase::Wait
0000008e25b2f980 000007f8ecf3d5b6 clr!Thread::intermediateThreadProc+0x7d
0000008e25b2fd00 000007f8ecf3d59f clr!Thread::intermediateThreadProc+0x66, calling clr!_chkstk
0000008e25b2fd40 000007f8f8281832 kernel32!BaseThreadInitThunk+0x1a
0000008e25b2fd70 000007f8f8aad609 ntdll!RtlUserThreadStart+0x1d
(...)

!threads -specialコマンドを使用して、最終的にこれらのスレッドが特別なGC スレッドであることがわかりました。

0:000> !threads -special
ThreadCount:      81
UnstartedThread:  0
BackgroundThread: 49
PendingThread:    0
DeadThread:       21
Hosted Runtime:   no
(...)
 OSID Special thread type
  1  804 DbgHelper 
  2  f48 GC 
  3  3f8 GC 
  4 1380 GC 
  5  af4 GC 
  6 1234 GC 
  7  fac GC 
  8 12e4 GC 
  9 17fc GC 
 10  644 GC 
 11 16e0 GC 
 12  6cc GC 
 13  9d4 GC 
 14  f7c GC 
 15  d5c GC 
 16  d74 GC 
 17  8d0 GC 
 18 1574 GC 
 19  8e0 GC 
 20  5bc GC 
 21  82c GC 
 22  e4c GC 
 23 129c GC 
 24  e28 GC 
 25  45c GC 
 26  340 GC 
 27 15c0 GC 
 28 16d4 GC 
 29  f4c GC 
 30 10e8 GC 
 31 1350 GC 
 32  164 GC 
 33 1620 GC 
 34 1444 Finalizer 
 35  c2c ProfilingAPIAttach 
 62   50 Timer 
 64 14a8 GC 
 65 145c GC 
 66  cdc GC 
 67  af8 GC 
 68 12e8 GC 
 69 1398 GC 
 70  e80 GC 
 71  a60 GC 
 72  834 GC 
 73  1b0 GC 
 74  2ac GC 
 75  eb8 GC 
 76  ec4 GC 
 77  ea8 GC 
 78   28 GC 
 79 11d0 GC 
 80 1700 GC 
 81 1434 GC 
 82 1510 GC 
 83   9c GC 
 84  c64 GC 
 85 11c0 GC 
 86 1714 GC 
 87 1360 GC 
 88 1610 GC 
 89  6c4 GC 
 90  cf0 GC 
 91 13d0 GC 
 92 1050 GC 
 93 1600 GC 
 94 16c4 GC 
 95 1558 GC 
 96 1b74 IOCompletion 
 97  ce4 ThreadpoolWorker 
 98 19a4 ThreadpoolWorker 
 99 1a00 ThreadpoolWorker 
100 1b64 ThreadpoolWorker 
101 1b38 ThreadpoolWorker 
102 1844 ThreadpoolWorker 
103 1b90 ThreadpoolWorker 
104 1a10 ThreadpoolWorker 
105 1894 Gate 

60 を超える "GC" スレッド... そこで、さまざまなサービス インスタンスの設定を確認したところ、問題のあるインスタンスは で構成されていて、GC Server他のインスタンスは構成されていないことがわかりました。

いくつかの詳細情報:

  • .NET 4.5 を使用しています
  • すべてのマシンで Windows 2012 Server を使用しています
  • バイ オクトコア サーバー (2 CPU、16 物理コア、32 論理コア) で実行します。

私が今やろうとしていること:

  • 他のダンプを取得しようとしています (プログラムにさらに多くのスレッドがある場合、プログラムがハングする場合など)。
  • 問題のあるインスタンスの設定を無効にしようとしGC Serverますが、問題が発生するまでに時間がかかる場合があります。

だからここに私の質問があります

  • GC サーバーで構成された .NET プログラムに非常に多くの GC スレッドがあるのは正常ですか? サーバー GC には、プロセッサごとに 1 つの GC スレッドしかないと思っていました。
  • これは、これらのサービスで見られる問題、つまり、時間の経過とともに何百ものスレッドが発生し、競合によるプロセスの巨大なフリーズに関連している可能性がありますか?
4

2 に答える 2

1

サーバー GC では、論理コアごとに 1 つのスレッドが存在します (つまり、そのコアにアフィニティが設定されます)。したがって、あなたの場合、少なくとも 32 のスレッドが必要です。バックグラウンド GC をオンにすると、各ヒープのグラフを処理するワーカー スレッドが増える可能性があります (参照)。

また、これらの GC スレッドは で実行さTHREAD_PRIORITY_HIGHESTれるため、GC によってまだ一時停止されていないスレッドを簡単に枯渇させる可能性があることに注意してください (参照)。

ここで、他のスレッドに関する限り、ガベージ コレクターに関係なく、プロセス内の 500 以上のスレッドが多くの競合を引き起こします。したがって、それらのスレッドが何であるかを理解することは、調査にとって重要です.


注目すべきこと

  • バックグラウンド GC がオンになっているかどうかを確認し、オンになっている場合は、それなしで実行してみてください (このモードは 4.5 のサーバー GC でサポートされています)。
  • スレッド プールのスレッドの最大数を減らしてみてください (32767 は異常な最大値です)。

procdump.exeを使用して、パフォーマンスが低下したときにミニダンプをキャプチャすることもできます。

于 2013-09-17T15:55:02.037 に答える
0

NUMA サーバーでも同様の問題が発生しました。私を助けたもの:

  • スレッドプールを制限する
  • ハングする管理対象プロセスのプロセッサ アフィニティ マスクを制限します。奇妙に見えますが、プロセスのプロセッサの数を減らすと、同時実行性の高い負荷でより速く動作することがあります。スピンロック (ビジーウェイト) が疑われます。
于 2013-10-22T06:47:24.893 に答える