当我从.NET生成一个新线程时到底发生了什么?

ole*_*sii 14 .net memory windows multithreading kernel

我想了解当我在.NET中生成一个新线程时,场景背后究竟发生了什么,如下所示:

Thread t = new Thread(DoWork); //I am not interested in DoWork per se
t.Start();
Run Code Online (Sandbox Code Playgroud)

1.在CLR和Windows内核中创建了哪些与线程相关的对象?
2.为什么需要这些物品?
3.在x86,x64 Windows上分配了多少托管/非托管内存(堆和堆栈)?

更新
我正在寻找托管线程对象这样的对象,我假设它是t,但也许是其他一些额外的托管对象; 内核线程对象,用户线程环境块等.

非常感谢!

Chr*_*ith 9

分配了Win32和内核内存

我不确定.NET部分是如何工作的,但是如果运行时决定用OS创建一个真正的线程,它最终会调用kernel32.dll中的Win32 API CreateThread,可能来自mscorlib.ni.dll

默认情况下,新线程为堆栈获取1MB的虚拟地址,并根据需要提交.这可以通过maxStackSize参数控制.主线程的堆栈大小来自可执行文件本身的参数.

在进程的地址空间中,将分配TEB(线程环境块)(另请参见).顺便提一下,x86上的FS寄存器指向线程本地存储和结构化异常处理(SEH)之类的东西.可能还有其他由Win32分配的未记录的内容.

在创建Win32线程时,将联系Win32服务器进程(csrss.exe).您可以看到csrss具有对Process Explorer中的所有Win32进程和线程开放的句柄,用于某种簿记.

将在进程中加载​​的DLL通知新线程,并可以分配自己的内存来跟踪线程.

内核将从内核非页面缓冲池创建ETHREAD[ layout ](从KTHREAD派生)对象来跟踪线程的状态.还将分配一个内核堆栈(x86默认为12k),可以将其分页(除非线程处于内核模式等待状态).

为什么这么多东西需要为线程分配内存

线程是操作系统提供的最小的抢先调度单元,并且有很多连接它们的上下文.许多不同的组件需要为每个线程提供单独的上下文,因为系统服务需要能够同时处理多个执行不同操作的线程.

某些服务要求您明确地向它们声明新线程,但大多数服务需要自动使用新线程.有时这意味着在线程启动时正确分配空间.当线程使用其他服务时,用于跟踪线程的内存量会随着这些服务为线程设置自己的上下文而增加.

分配了多少内存

很难说为一个线程分配了多少内存,因为它分布在几个地址空间和堆上.它将在Windows版本,已安装组件和当前加载到进程中的内容之间有所不同.

最大的成本通常被认为是新线程默认使用的1MB地址空间,但即使这个限制也可以允许在单个进程中使用数百个而不会耗尽空间.

如果设计使用的OS线程数多于系统中CPU的数量,则应对其进行检查.具有线程池和轻量级线程的工作队列以及使用光纤或其他库实现的用户模式调度应该能够处理多线程处理而不需要过多的OS线程,从而使线程的内存成本变得不重要.