.NET常见线程简介
2009-01-30 10:41
218 查看
原文地址:http://blogs.msdn.com/tess/archive/2005/12/20/505862.aspx
当你分析一个dump文件的时候,调试里面最艺术的地方就是知道哪些东西是可以忽略的,而哪些是你想要的东西。
特别是在你分析一个程序停止响应(hang)的bug时,了解这些常见线程对你非常有帮助,浏览线程各堆栈列表的时候,你可以知道不是这个线程出问题了,也不是那个线程…………
因为大部分时间我是跟asp.net打交道,所以我将通过分析w3wp.exe(IIS6里面用来执行asp.net页面代码的进程)的一个dump文件来介绍这些常见线程。所有这些常见线程都有一个共性,就是它们要么是睡眠状态(sleepingstate)或者等待状态(waitingstate),等待处理更多的工作。因此虽然它们看起来是造成程序停止响应(hang)的原因,实际上它们并不是真正的罪魁祸首……如果你发现它们处于其他的状态,比如说正在执行某个任务,那么它们就需要得到更多的关注了。
我把这些常见的线程划分为以下几个种类:
1.CLR线程
2.W3WP线程
3.RPC线程
4.其他COM线程
CLR线程
线程池(ThreadPool)管理程序有五种主要的线程类型:
1.CompletionPort/IO线程和工作(Worker)线程是执行你的托管(managed)代码和.net代码的线程。
2.一个闸门(gate)线程根据CPU的利用率,GC的频率和工作队列(workerqueue)的大小,动态地创建或销毁工作线程和IO线程。
3.停滞(wait)线程,用来等待一些同步对象触发的事件,比如说,一个程序员使用WaitHandle类(或它的派生类),这个类内部使用WaitForSingleObjectWin32API函数来是这个线程处于停滞状态。
4.最后第五个是定时器(Timer)线程,它是用来调用定时器(Timer)回调函数的线程。
下面的列表列出了.NET1.1中它们在停滞状态时候的模样(由于我在翻译的时候,机器上没有微软.NET2.0的公开符号文件,所以只好原文拷贝下来了,有机会我会将2.0里面的堆栈列出来):
闲置状态中的CLR工作线程(WorkerThread):
闲置状态中的CLRCompletionPort/IOThread:
闲置状态中的CLR闸门(gate)线程:
闲置状态中的CLR停滞(wait)线程:
闲置状态中的CLR定时器(Timer)线程:
除了这些线程,CLR还创建了一些其他的线程:
在一个多核主机上,在一个CLR宿主进程中(服务器版本的GC),每一个处理器都会由一个垃圾回收(GC)线程,而在超线程系统上,每个进程会有两个。这些线程用来处理托管堆上的垃圾回收操作。
另外在每一个进程里我们还有终结器线程(FinalizerThread),这个线程运行所有的Finalize函数。在调试进程无响应(hang)和高内存使用率的情形时,要特别注意这个线程。如果在收集一个对象(finalizinganobject)的时候它被其他的东西阻塞(blockedinanyway)的话,那么你的托管变量就不能被以合适的方式清理掉,最终你就得到一个内存泄漏的结果,并且/或者有一个高CPU使用率的情形,因为GC将不得不重复启动以保证你的内存可用率。
最后,CLR还提供了一个DebuggerThread用来提供托管程序调试服务。
闲置状态中的CLR垃圾回收(GC)线程:
闲置状态中的CLR终结器(Finalizer)线程:
闲置状态中的CLR调试(Debugger)线程:
W3WP线程
W3WP进程里面主要有主线程、线程池线程和压缩线程。
主线程负责启动和关闭进程,线程池线程用来处理页面请求,而压缩线程就如名字如表明的那样是用来处理压缩数据的。
W3WP主(main)线程:
闲置状态中的w3wp线程池(ThreadPool)线程:
闲置状态中的w3wp压缩(Compression)线程:
RPC线程
当有闲置的LRPC工作线程(workerthread)存在的时候,意味着我们可以处理更多的本地或者远程COM对象激活和本地COM函数调用。
有闲置RPC工作线程(workerthread)存在意味着我们可以处理更多的远程COM函数调用。
参看这篇文档来了解RPC线程模型:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/rpc/rpc/scalability.asp
闲置状态中的RPC工作(worker)线程:
闲置状态中的LRPC工作(worker)线程:
其他COM线程
单线程组件必须被Host(Main)STA线程处理—这个线程是第一个被创建的COMSTA线程。
有闲置的STA线程存在的时候意味着我们可以处理更多的STA激活和函数调用。
参考来获取更多的信息:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dncomser/html/comthread.asp。
HostSTA线程:
闲置的STA线程:
备注:这不是一个完整的线程列表,但是上面这些可以在你分析导致你的进程没有响应的嫌疑犯的时候提供一些有用的信息。
当你分析一个dump文件的时候,调试里面最艺术的地方就是知道哪些东西是可以忽略的,而哪些是你想要的东西。
特别是在你分析一个程序停止响应(hang)的bug时,了解这些常见线程对你非常有帮助,浏览线程各堆栈列表的时候,你可以知道不是这个线程出问题了,也不是那个线程…………
因为大部分时间我是跟asp.net打交道,所以我将通过分析w3wp.exe(IIS6里面用来执行asp.net页面代码的进程)的一个dump文件来介绍这些常见线程。所有这些常见线程都有一个共性,就是它们要么是睡眠状态(sleepingstate)或者等待状态(waitingstate),等待处理更多的工作。因此虽然它们看起来是造成程序停止响应(hang)的原因,实际上它们并不是真正的罪魁祸首……如果你发现它们处于其他的状态,比如说正在执行某个任务,那么它们就需要得到更多的关注了。
我把这些常见的线程划分为以下几个种类:
1.CLR线程
2.W3WP线程
3.RPC线程
4.其他COM线程
CLR线程
线程池(ThreadPool)管理程序有五种主要的线程类型:
1.CompletionPort/IO线程和工作(Worker)线程是执行你的托管(managed)代码和.net代码的线程。
2.一个闸门(gate)线程根据CPU的利用率,GC的频率和工作队列(workerqueue)的大小,动态地创建或销毁工作线程和IO线程。
3.停滞(wait)线程,用来等待一些同步对象触发的事件,比如说,一个程序员使用WaitHandle类(或它的派生类),这个类内部使用WaitForSingleObjectWin32API函数来是这个线程处于停滞状态。
4.最后第五个是定时器(Timer)线程,它是用来调用定时器(Timer)回调函数的线程。
下面的列表列出了.NET1.1中它们在停滞状态时候的模样(由于我在翻译的时候,机器上没有微软.NET2.0的公开符号文件,所以只好原文拷贝下来了,有机会我会将2.0里面的堆栈列出来):
闲置状态中的CLR工作线程(WorkerThread):
11Id:fb8.268Suspend:0Teb:7ffaa000Unfrozen ChildEBPRetAddrArgstoChild 0199fdf87c82212477e6baa80000023400000000ntdll!KiFastSystemCallRet 0199fdfc77e6baa800000234000000000199fe40ntdll!NtWaitForSingleObject+0xc 0199fe6c77e6ba120000023400009c4000000000kernel32!WaitForSingleObjectEx+0xac 0199fe80791d401f0000023400009c4000000000kernel32!WaitForSingleObject+0x12 0199fea4791fdacc000000000000000080a56bccmscorsvr!ThreadpoolMgr::WorkerThreadStart+0x3a 0199ffb877e66063000b6da80000000000000000mscorsvr!ThreadpoolMgr::intermediateThreadProc+0x44 0199ffec00000000791fda8b000b6da800000000kernel32!BaseThreadStart+0x34 |
9Id:fb8.ef8Suspend:0Teb:7ffac000Unfrozen ChildEBPRetAddrArgstoChild 0191fec07c821bf477e6611a0000023c0191ff1cntdll!KiFastSystemCallRet 0191fec477e6611a0000023c0191ff1c0191ff08ntdll!NtRemoveIoCompletion+0xc 0191fef0791fdb220000023c0191ff180191ff1ckernel32!GetQueuedCompletionStatus+0x29 0191ff24791fdacc00000001809a05fe7ffac000mscorsvr!ThreadpoolMgr::CompletionPortThreadStart+0x49 0191ffb877e66063000b6da80000000000000000mscorsvr!ThreadpoolMgr::intermediateThreadProc+0x44 0191ffec00000000791fda8b000b6da800000000kernel32!BaseThreadStart+0x34 |
10Id:fb8.bdcSuspend:0Teb:7ffab000Unfrozen ChildEBPRetAddrArgstoChild 0195fe507c82136477e42439000000000195fe94ntdll!KiFastSystemCallRet 0195fe5477e42439000000000195fe9400000000ntdll!NtDelayExecution+0xc 0195febc77e424b7000001f4000000000195ffb8kernel32!SleepEx+0x68 0195fecc791bf4f9000001f40b2646e600000939kernel32!Sleep+0xf 0195ffb877e66063000000000000000000000000mscorsvr!ThreadpoolMgr::GateThreadStart+0x54 0195ffec00000000791bf4a50000000000000000kernel32!BaseThreadStart+0x34 |
25Id:230.ac0Suspend:0Teb:7ff4c000Unfrozen ChildEBPRetAddrArgstoChild 1b88ff6c7c573a4e000000011b88ff8400000000NTDLL!ZwDelayExecution+0xb 1b88ff8c7923558cffffffff00000001198ba828KERNEL32!SleepEx+0x32 1b88ffb47c57438b00000000198ba828197f7498mscorsvr!ThreadpoolMgr::WaitThreadStart+0x45 1b88ffec000000007923556a1973b3d000000000KERNEL32!BaseThreadStart+0x52 |
18Id:fb8.914Suspend:0Teb:7ff5f000Unfrozen ChildEBPRetAddrArgstoChild 0224ff387c82136477e42439000000010224ff7cntdll!KiFastSystemCallRet 0224ff3c77e42439000000010224ff7c000003e8ntdll!NtDelayExecution+0xc 0224ffa4791cc578000003e80000000100000000kernel32!SleepEx+0x68 0224ffb877e66063000000000000000000000000mscorsvr!ThreadpoolMgr::TimerThreadStart+0x30 0224ffec00000000791cc5480000000000000000kernel32!BaseThreadStart+0x34 |
在一个多核主机上,在一个CLR宿主进程中(服务器版本的GC),每一个处理器都会由一个垃圾回收(GC)线程,而在超线程系统上,每个进程会有两个。这些线程用来处理托管堆上的垃圾回收操作。
另外在每一个进程里我们还有终结器线程(FinalizerThread),这个线程运行所有的Finalize函数。在调试进程无响应(hang)和高内存使用率的情形时,要特别注意这个线程。如果在收集一个对象(finalizinganobject)的时候它被其他的东西阻塞(blockedinanyway)的话,那么你的托管变量就不能被以合适的方式清理掉,最终你就得到一个内存泄漏的结果,并且/或者有一个高CPU使用率的情形,因为GC将不得不重复启动以保证你的内存可用率。
最后,CLR还提供了一个DebuggerThread用来提供托管程序调试服务。
闲置状态中的CLR垃圾回收(GC)线程:
13Id:fb8.c10Suspend:0Teb:7ffa8000Unfrozen ChildEBPRetAddrArgstoChild 01d6fefc7c82212477e6baa8000002b400000000ntdll!KiFastSystemCallRet 01d6ff0077e6baa8000002b40000000000000000ntdll!NtWaitForSingleObject+0xc 01d6ff7077e6ba12000002b4ffffffff00000000kernel32!WaitForSingleObjectEx+0xac 01d6ff84791fe6b0000002b4ffffffff00000000kernel32!WaitForSingleObject+0x12 01d6ffac792356be0000000001d6ffec77e66063mscorsvr!gc_heap::gc_thread_function+0x2f 01d6ffb877e66063000d2ed80000000000000000mscorsvr!gc_heap::gc_thread_stub+0x1e 01d6ffec00000000792356a0000d2ed800000000kernel32!BaseThreadStart+0x34 |
17Id:fb8.7b0Suspend:0Teb:7ffa4000Unfrozen ChildEBPRetAddrArgstoChild 01e6fdf87c82211477e6711b0000000201e6fe48ntdll!KiFastSystemCallRet 01e6fdfc77e6711b0000000201e6fe4800000001ntdll!NtWaitForMultipleObjects+0xc 01e6fea477e6107500000002793eee0800000000kernel32!WaitForMultipleObjectsEx+0x11a 01e6fec07927826b00000002793eee0800000000kernel32!WaitForMultipleObjects+0x18 01e6fee0791fecf4000002dc00000000792376a4mscorsvr!WaitForFinalizerEvent+0x5a 01e6ff247924568100000000809a05fe7ffa4000mscorsvr!GCHeap::FinalizerThreadStart+0x96 01e6ffb877e66063000d55000000000000000000mscorsvr!Thread::intermediateThreadProc+0x44 01e6ffec0000000079245640000d550000000000kernel32!BaseThreadStart+0x34 |
12Id:fb8.b30Suspend:0Teb:7ffa9000Unfrozen ChildEBPRetAddrArgstoChild 01adfe707c82211477e6711b0000000301adfec0ntdll!KiFastSystemCallRet 01adfe7477e6711b0000000301adfec000000001ntdll!NtWaitForMultipleObjects+0xc 01adff1c77e610750000000301adff5c00000000kernel32!WaitForMultipleObjectsEx+0x11a 01adff3879238fd60000000301adff5c00000000kernel32!WaitForMultipleObjects+0x18 01adffa079238f4d000000000000000000000000mscorsvr!DebuggerRCThread::MainLoop+0x90 01adffb07923a71401adffec77e66063019d1eb0mscorsvr!DebuggerRCThread::ThreadProc+0x68 01adffb877e66063019d1eb00000000000000000mscorsvr!DebuggerRCThread::ThreadProcStatic+0xb 01adffec000000007923a709019d1eb000000000kernel32!BaseThreadStart+0x34 |
W3WP进程里面主要有主线程、线程池线程和压缩线程。
主线程负责启动和关闭进程,线程池线程用来处理页面请求,而压缩线程就如名字如表明的那样是用来处理压缩数据的。
W3WP主(main)线程:
.0Id:fb8.fd8Suspend:0Teb:7ffdf000Unfrozen ChildEBPRetAddrArgstoChild 0006fc087c82212477e6baa80000018400000000ntdll!KiFastSystemCallRet 0006fc0c77e6baa8000001840000000000000000ntdll!NtWaitForSingleObject+0xc 0006fc7c77e6ba1200000184ffffffff00000000kernel32!WaitForSingleObjectEx+0xac 0006fc905a36467a00000184ffffffff00000000kernel32!WaitForSingleObject+0x12 0006fca05a366e6300254ff85a3af41d00000000w3dt!WP_CONTEXT::RunMainThreadLoop+0x10 0006fca85a3af41d0000000064711da900000000w3dt!UlAtqStartListen+0x2d 0006fcb85a3bc2590100141c010013e4010012d0w3core!W3_SERVER::StartListen+0xbd 0006ff0c0100187c00000007002538e000000000w3core!UlW3Start+0x26e 0006ff4401001a2300000007002538e0002543d0w3wp!wmain+0x22a 0006ffc077e523cd00000000000000007ffd7000w3wp!wmainCRTStartup+0x12b 0006fff000000000010018f80000000078746341kernel32!BaseProcessStart+0x23 |
2Id:fb8.c5cSuspend:0Teb:7ffd9000Unfrozen ChildEBPRetAddrArgstoChild 00c8ff247c821bf477e6611a0000017000c8ff80ntdll!KiFastSystemCallRet 00c8ff2877e6611a0000017000c8ff8000c8ff6cntdll!NtRemoveIoCompletion+0xc 00c8ff545a30249e0000017000c8ff7c00c8ff80kernel32!GetQueuedCompletionStatus+0x29 00c8ff8c5a3026bc00000000002585805a300000w3tp!THREAD_POOL_DATA::ThreadPoolThread+0x33 00c8ffa05a301db9000001020000000000000000w3tp!THREAD_POOL_DATA::ThreadPoolThread+0x24 00c8ffb877e66063002585800000000000000000w3tp!THREAD_MANAGER::ThreadManagerThread+0x39 00c8ffec000000005a301d800025858000000000kernel32!BaseThreadStart+0x34 |
7Id:fb8.b20Suspend:0Teb:7ffaf000Unfrozen ChildEBPRetAddrArgstoChild 017dfa847c82212477e6baa8000001d000000000ntdll!KiFastSystemCallRet 017dfa8877e6baa8000001d00000000000000000ntdll!NtWaitForSingleObject+0xc 017dfaf877e6ba12000001d0ffffffff00000000kernel32!WaitForSingleObjectEx+0xac 017dfb0c5a3b8147000001d0ffffffff00000000kernel32!WaitForSingleObject+0x12 017dffb877e66063000000000000000000000000w3core!HTTP_COMPRESSION::CompressionThread+0x126 017dffec000000005a3b80210000000000000000kernel32!BaseThreadStart+0x34 |
当有闲置的LRPC工作线程(workerthread)存在的时候,意味着我们可以处理更多的本地或者远程COM对象激活和本地COM函数调用。
有闲置RPC工作线程(workerthread)存在意味着我们可以处理更多的远程COM函数调用。
参看这篇文档来了解RPC线程模型:
闲置状态中的RPC工作(worker)线程:
29Id:fb8.7fcSuspend:0Teb:7ffa1000Unfrozen ChildEBPRetAddrArgstoChild 02ddfeac7c821bf477e6611a0000007802ddff04ntdll!KiFastSystemCallRet 02ddfeb077e6611a0000007802ddff0402ddfef4ntdll!NtRemoveIoCompletion+0xc 02ddfedc77c604c30000007802ddff1402ddff04kernel32!GetQueuedCompletionStatus+0x29 02ddff1877c60655ffffffff02ddff6c02ddff70rpcrt4!COMMON_ProcessCalls+0xa1 02ddff8477c5f9f102ddffac77c5f7dd00090250rpcrt4!LOADABLE_TRANSPORT::ProcessIOEvents+0x117 02ddff8c77c5f7dd000902500000000000000000rpcrt4!ProcessIOEventsWrapper+0xd 02ddffac77c5de880008e61002ddffec77e66063rpcrt4!BaseCachedThreadRoutine+0x9d 02ddffb877e66063029515e80000000000000000rpcrt4!ThreadStartRoutine+0x1b 02ddffec0000000077c5de6d029515e800000000kernel32!BaseThreadStart+0x34 |
33Id:fb8.b24Suspend:0Teb:7ffdb000Unfrozen ChildEBPRetAddrArgstoChild 02e1fe187c821c5477c7538c0000013802e1ff74ntdll!KiFastSystemCallRet 02e1fe1c77c7538c0000013802e1ff7400000000ntdll!ZwReplyWaitReceivePortEx+0xc 02e1ff8477c5778f02e1ffac77c5f7dd0009d660rpcrt4!LRPC_ADDRESS::ReceiveLotsaCalls+0x198 02e1ff8c77c5f7dd0009d6600000000000000000rpcrt4!RecvLotsaCallsWrapper+0xd 02e1ffac77c5de880008e61002e1ffec77e66063rpcrt4!BaseCachedThreadRoutine+0x9d 02e1ffb877e6606305057c080000000000000000rpcrt4!ThreadStartRoutine+0x1b 02e1ffec0000000077c5de6d05057c0800000000kernel32!BaseThreadStart+0x34 |
单线程组件必须被Host(Main)STA线程处理—这个线程是第一个被创建的COMSTA线程。
有闲置的STA线程存在的时候意味着我们可以处理更多的STA激活和函数调用。
参考来获取更多的信息:
HostSTA线程:
31Id:fb8.b3cSuspend:0Teb:7ff4e000Unfrozen ChildEBPRetAddrArgstoChild 049cff147739c78d7739c7c0049cff5800000000ntdll!KiFastSystemCallRet 049cff3477694ff1049cff580000000000000000user32!NtUserGetMessage+0xc 049cff74776cf35b0000753077e6ba2002a40fe0ole32!CDllHost::STAWorkerLoop+0x72 049cff90776cf2a3049cffb8776b230777790438ole32!CDllHost::WorkerThread+0xc8 049cff98776b2307777904380000000002a40fe0ole32!DLLHostThreadEntry+0xd 049cffac776b237400000000049cffec77e66063ole32!CRpcThread::WorkerLoop+0x1e 049cffb877e6606302a40fe00000000000000000ole32!CRpcThreadCache::RpcWorkerThreadEntry+0x20 049cffec00000000776b235402a40fe000000000kernel32!BaseThreadStart+0x34 |
14Id:e5c.d90Suspend:1Teb:7ffac000Unfrozen ChildEBPRetAddrArgstoChild 0140fdcc77f4372d77e41bfa000000030140fe1cSharedUserData!SystemCallStub+0x4 0140fdd077e41bfa000000030140fe1c00000001ntdll!NtWaitForMultipleObjects+0xc 0140fe7877d076f5000000030140fea000000000kernel32!WaitForMultipleObjectsEx+0x11a 0140fed477d077f5000000020140ff74ffffffffUSER32!RealMsgWaitForMultipleObjectsEx+0x13f 0140fef07563439d000000020140ff7400000000USER32!MsgWaitForMultipleObjects+0x1d 0140ff8477bc91ed000b6eb80000000000000000COMSVCS!CSTAThread::WorkerLoop+0x1e3 0140ffb877e4a99000268a580000000000000000msvcrt!_threadstartex+0x6f 0140ffec0000000077bc917e00268a5800000000kernel32!BaseThreadStart+0x34 |
相关文章推荐
- .NET常见线程简介
- RxJava2.0学习笔记(简介,线程控制,常见操作符)
- .Net线程常见问题和误解解答集锦
- 分享.net常见的内存泄露及解决方法
- .net反射简介
- 基于zookeeper的线程及其zookeeper简介
- .net反射简介 - 概述
- 线程属性pthread_attr_t简介
- JQuery FlexiGrid的asp.net完美解决方案:dotNetFlexGrid-.Net原生的异步表格控件 简介和应用效果截图
- 常见的进程和线程知识了解
- .NET类库简介(zhuan)
- C#高级编程六十九天----DLR简介 .在.NET中使用DLR(转载) 我也来说说Dynamic
- .NET别名机制简介
- 使用.net开发手机管理软件 (四) AT指令简介
- C#线程操作常见的六大操作方法
- 杨航 简介 —— 应聘 .NET 方向
- 几种常见的NoSql数据库简介
- .Net中的不可变集合(Immutable Collection)简介
- .NET中对资源文件的使用简介