Почему количество потоков, сообщаемых WinDbg, диспетчером задач и VS Debugger, отличается?

В то время как мое приложение .Net 3.5 работало, диспетчер задач Windows показал, что в моем приложении было 16 потоков. Я собрал дамп памяти для процесса и открыл его с помощью WinDbg/SOS.

Запуск команды! показывает, что у меня есть:

ThreadCount: 456
UnstartedThread: 0
BackgroundThread: 6
PendingThread: 0
DeadThread: 449
Hosted Runtime: no

Вот первые несколько строк вывода нитей:

       ID OSID ThreadOBJ    State     GC       Context       Domain   Count APT Exception
   0    1 2848 004366a8      6020 Enabled  11738178:11738778 0042a9f0     0 STA
   2    2 1820 004430e0      b220 Enabled  00000000:00000000 0042a9f0     0 MTA (Finalizer)
   7    5 2c38 055d6330    80a220 Enabled  00000000:00000000 0042a9f0     0 MTA (Threadpool Completion Port)
   8    4  e18 04116900   180b220 Enabled  1157cdc8:1157e778 0042a9f0     0 MTA (Threadpool Worker)
XXXX    6    0 055f94b0      9820 Enabled  00000000:00000000 0042a9f0     0 Ukn
XXXX    7    0 05649228      9820 Enabled  00000000:00000000 0042a9f0     0 MTA
XXXX    8    0 0567d4f8      9820 Enabled  00000000:00000000 0042a9f0     0 Ukn
XXXX    9    0 05688d68      9820 Enabled  00000000:00000000 0042a9f0     0 Ukn
XXXX    a    0 056fd680      9820 Enabled  00000000:00000000 0042a9f0     0 MTA
XXXX    b    0 0575d7f0      9820 Enabled  00000000:00000000 0042a9f0     0 Ukn
XXXX    c    0 056fd250      9820 Enabled  00000000:00000000 0042a9f0     0 Ukn
XXXX    d    0 0572a780      9820 Enabled  00000000:00000000 0042a9f0     0 Ukn
XXXX    e    0 0f082668      9820 Enabled  00000000:00000000 0042a9f0     0 Ukn
XXXX    f    0 0f082a38      9820 Enabled  00000000:00000000 0042a9f0     0 Ukn
XXXX   10    0 0570ca68      9820 Enabled  00000000:00000000 0042a9f0     0 Ukn
XXXX   11    0 0570ce50      9820 Enabled  00000000:00000000 0042a9f0     0 Ukn
  10   12 3fb0 0570d238   180b220 Enabled  00000000:00000000 0042a9f0     0 MTA (Threadpool Worker)
XXXX   13    0 0570d620      9820 Enabled  00000000:00000000 0042a9f0     0 Ukn
XXXX   14    0 0570da08      9820 Enabled  00000000:00000000 0042a9f0     0 Ukn
XXXX   15    0 0570ddf0      9820 Enabled  00000000:00000000 0042a9f0     0 Ukn
XXXX   16    0 0570e1d8      9820 Enabled  00000000:00000000 0042a9f0     0 Ukn
XXXX   17    0 0570e5c0      9820 Enabled  00000000:00000000 0042a9f0     0 Ukn
XXXX   18    0 0579e540      9820 Enabled  00000000:00000000 0042a9f0     0 Ukn
XXXX   19    0 0579e928      9820 Enabled  00000000:00000000 0042a9f0     0 Ukn
XXXX   1a    0 0579ed10      9820 Enabled  00000000:00000000 0042a9f0     0 Ukn
XXXX   1b    0 0579f0f8      9820 Enabled  00000000:00000000 0042a9f0     0 Ukn
XXXX   1c    0 0579f4e0      9820 Enabled  00000000:00000000 0042a9f0     0 Ukn
XXXX   1d    0 0579f8c8      9820 Enabled  00000000:00000000 0042a9f0     0 Ukn
XXXX   1e    0 0579fcb0      9820 Enabled  00000000:00000000 0042a9f0     0 Ukn
XXXX   1f    0 057a0098      9820 Enabled  00000000:00000000 0042a9f0     0 Ukn
XXXX   20    0 057a0480      9820 Enabled  00000000:00000000 0042a9f0     0 Ukn

Если я присоединю Visual Studio Debugger к запущенному процессу, окна Threads показывают 7 потоков.

У меня есть несколько вопросов:

  • Почему WinDbg говорит, что есть 456 потоков, а диспетчер задач говорит 16
  • Почему диспетчер задач говорит, что есть 16 потоков, а Visual Studio Debugger говорит 7
  • Команда!! показывает, что все эти мертвые потоки не имеют значения OSID. Означает ли это, что они больше не известны ОС и являются просто объектами .Net, которые расположены вокруг? Что такое мертвая нить?
  • Должен ли я беспокоиться о большом количестве мертвых потоков?

РЕДАКТИРОВАТЬ 11 февраля 2010:. Здесь представлена ​​более подробная информация о моем приложении. Мы используем фоновые потоки для опроса сервера и выполнения других задач. Эти задачи выполняются каждые несколько минут. Мы не используем пул потоков .Net.

EDIT 18 февраля 2010: Я исправил утечку управляемого объекта в нашей программе (благодаря @highphilosopher). Однако мой вопрос о том, почему WinDbg, Task Manager и VS Debugger не согласен с количеством потоков, все еще остается без ответа. Может кто-нибудь объяснить?

EDIT 1 марта 2010 года: Мне все еще интересно узнать, почему Task Manager и Visual Studio Debugger не согласны с количеством потоков. Почему Visual Studio фильтрует некоторые потоки? Какие потоки отфильтровываются?

Ответ 1

Диспетчер задач сообщает общее количество потоков для вашего процесса, а !threads сообщает количество управляемых потоков. Если вы используете команду ~ в WinDbg, вы увидите все потоки потоков для процесса.

На выходе из !threads на вашем выходе отображается много мертвых потоков. Нити, перечисленные в XXXX для id, - это потоки, которые прекратились, но соответствующие объекты потока еще не собраны. То есть сообщенный номер намного выше фактического количества потоков. Число счетчиков потоков указывает, что 449 из 456 потоков мертвы.

Я нахожу количество потоков высоким, и если приложение было бездействующим, странно, что все еще существует, но без дополнительной информации трудно быть более конкретным.

Ответ 2

Я предполагаю, что пул потоков имел периоды большой нагрузки, а затем уничтожал потоки, когда загрузка утихла.

Ответ 3

То, что вы видите, похоже на ссылку на эти потоки в другом потоке. Поскольку поток ссылается, он не может быть собран GC. Поток завершил выполнение метода, который он был отправлен, чтобы он не находился ни в состоянии сна, ни в состоянии запуска, поэтому он должен быть мертвым. Проверьте свой код на коллекцию потоков или что-то подобное. Возможно, событие, которое привязывается к потоку, но никогда не отцепляется?

Ответ 4

Другая причина, по которой подсчет потоков не будет соответствовать, заключается в том, что диспетчер задач собирает информацию с использованием неинвазивных методов. Обычно отладчик и по умолчанию использует инвазивное приложение.

Это означает, что любое время вы отлаживаете запущенное приложение Windows, API отладки вводит удаленный поток в целевое приложение и вызываете KERNEL32! DebugBreak, который является int3 (0xcc) инструкция. На этом этапе процесс прерывается и прекращает выполнение, однако теперь у вас есть хотя бы один дополнительный поток отладки.