为什么 WinDbg、任务管理器和 VS 调试器报告的线程数不同?
当我的 .Net 3.5 应用程序运行时,Windows 任务管理器显示我的应用程序有 16 个线程。我收集了该进程的内存转储并使用 WinDbg/SOS 打开它。
运行 !threads 命令显示我有:
ThreadCount: 456
UnstartedThread: 0
BackgroundThread: 6
PendingThread: 0
DeadThread: 449
Hosted Runtime: no
以下是 !threads 输出的前几行:
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 调试器附加到正在运行的进程,“线程”窗口将显示 7 个线程。
我有几个问题:
- 为什么 WinDbg 说有 456 个线程,而任务管理器说 16
- 为什么任务管理器说有 16 个线程,而 Visual Studio 调试器说 7
- !thread 命令显示所有这些死线程都没有 OSID价值。这是否意味着操作系统不再知道它们,而只是布局周围的 .Net 对象?到底什么是死线程?
- 我应该担心大量死线程吗?
2010 年 2 月 11 日编辑:以下是有关我的应用程序的更多信息。我们使用后台线程来轮询服务器并执行其他任务。这些任务每隔几分钟执行一次。我们不使用.Net 线程池。
2010 年 2 月 18 日编辑:我修复了程序中的托管 Thread 对象泄漏(感谢 @highphilosopher)。然而,我关于为什么 WinDbg、任务管理器和 VS 调试器在线程数上不一致的问题仍然没有答案。谁能解释一下吗?
2010 年 3 月 1 日编辑: 我仍然有兴趣了解为什么任务管理器和 Visual Studio 调试器在线程数上不一致。为什么 Visual Studio 会过滤某些线程?它过滤掉什么样的线程?
While my .Net 3.5 app was running, the Windows Task Manager shown that my app had 16 threads. I collected a memory dump for the process and opened it using WinDbg/SOS.
Running the !threads command reveals that I have :
ThreadCount: 456
UnstartedThread: 0
BackgroundThread: 6
PendingThread: 0
DeadThread: 449
Hosted Runtime: no
Here are the first few lines of the !threads output:
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
If I attach the Visual Studio Debugger to the running process, the Threads windows shows 7 threads.
I have a few questions:
- Why does WinDbg say there are 456 threads and Task Manager says 16
- Why does Task Manager say there are 16 threads and Visual Studio Debugger says 7
- The !thread command shows that all those dead threads don't have a OSID value. Does that mean they are no longer known to the OS are and just .Net objects that are layout around? What is a dead thread exactly?
- Should I worry about the high number of dead threads?
EDIT Feb 11th 2010: Here is more information about my app. We use background threads to poll the server and perform other tasks. Those tasks are executed every few minutes. We do not use the .Net Thread Pool.
EDIT Feb 18th 2010: I fixed the managed Thread object leak in our program (thanks to @highphilosopher). However, my question about why WinDbg, Task Manager and VS Debugger don't agree on the number of threads is still unanswered. Can anyone explain?
EDIT Mar 1st 2010: I'm still interested in knowing why Task Manager and Visual Studio Debugger don't agree on the number of threads. Why does Visual studio filter some of the threads? What kind of threads does it filter out?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
任务管理器报告进程的线程总数,而
!threads
报告托管线程数。如果您在 WinDbg 中使用~
命令,您将看到该进程的所有线程。输出中
!threads
的输出显示了许多死线程。 id 为XXXX
列出的线程是已终止但尚未收集相应线程对象的线程。即报告的数量远高于实际的线程数。线程计数显示 456 个线程中有 449 个已死亡。我发现线程数量很高,如果应用程序一直处于空闲状态,那么它们仍然存在就很奇怪,但如果没有进一步的信息,很难更具体。
Task manager reports the total number of threads for your process while
!threads
reports the number of managed threads. If you use the~
command in WinDbg you will see all thread threads for the process.The output from
!threads
in your output shows a lot of dead threads. The threads listed withXXXX
for id are threads that have terminated but the corresponding thread objects have not yet been collected. I.e. the reported number is much higher than the actual number of threads. The thread count numbers state that 449 of the 456 threads are dead.I find the number of threads high and if the application has been idle it is odd that the're still around, but without further info it is hard to be more specific.
我的猜测是线程池有一段时期的重负载,然后在负载消失时杀死线程。
My guess is the thread pool had periods of heavy load and then killed the threads when the load died down.
您所看到的听起来像是您在不同的线程上引用了这些线程。由于该线程已被引用,因此无法被 GC 收集。该线程已完成执行发送给它的方法,因此它既不处于睡眠状态,也不处于可运行状态,因此它一定是死亡的。检查您的代码中是否有线程集合或类似内容。也许是一个被线程钩住但从未脱钩的事件?
What you're seeing sounds like you have a reference to these threads on a different thread. Since the thread is referenced it can't be Collected by the GC. The thread has completed execution of the method that it was sent to do so it is in neither a sleep state, nor runnable state, so it must be dead. Check your code for a Collection of threads or something similar. Perhaps an event that gets hooked to by the thread, but never unhooked?
线程计数不匹配的另一个原因是任务管理器使用非侵入性技术收集信息。调试器通常且默认情况下使用侵入式附加。
这意味着,任何时候您调试正在运行的 Windows 应用程序时,调试 API 都会将远程线程注入目标应用程序并调用 KERNEL32!DebugBreak,这是一条 int3 (0xcc) 指令。此时,进程中断并停止执行,但是,您现在至少有一个额外的调试线程正在运行。
Another reason why the thread counts will not match is that Task Manager collects information using noninvasive techniques. A debugger usually, and by default uses an invasive attach.
What this means, is that, any time you debug a running windows application, the debug API inject's a remote thread into the target application and call's KERNEL32!DebugBreak, which is an int3 (0xcc) instruction. At this point the process breaks and stop's executing, however, you now have at least one additional debug thread running.