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 スレッドしかないと思っていました。
- これは、これらのサービスで見られる問題、つまり、時間の経過とともに何百ものスレッドが発生し、競合によるプロセスの巨大なフリーズに関連している可能性がありますか?