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

标签 .net windows multithreading memory kernel

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

Thread t = new Thread(DoWork); //I am not interested in DoWork per se
t.Start();

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

更新
我正在寻找诸如托管线程对象之类的对象,我假设它是t,但也许还有其他一些其他托管对象; 内核线程对象用户线程环境 block 等。

非常感谢!

最佳答案

分配的 Win32 和内核内存

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

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

在进程的地址空间中,TEB (线程环境 block )将被分配(see also)。顺便说一下,x86 上的 FS 寄存器指向这个,用于线程本地存储和结构化异常处理 (SEH)。可能还有其他由 Win32 分配的没有记录的东西。

在创建 Win32 线程时,会联系 Win32 服务器进程 (csrss.exe)。您可以看到 csrss 在 Process Explorer 中为所有 Win32 进程和线程打开了句柄,以进行某种记账。

进程中加载​​的 DLL 将收到新线程的通知,并可能分配自己的内存来跟踪线程。

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

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

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

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

分配了多少内存

很难说为线程分配了多少内存,因为它分布在多个地址空间和堆中。它会因 Windows 版本、安装的组件以及当前加载到进程中的内容而异。

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

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

关于.net - 当我从 .NET 生成一个新线程时到底发生了什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6300598/

相关文章:

c# - 组织 using 指令,重新运行测试?

c# - 如何在嵌套数组上使用日期范围查询Elasticsearch?

php - 确保仅预授权个人访问应用程序

windows - git bash 终端增加要查看的行数(windows)

C++ 多线程应用程序永远挂起

java - 我正在尝试了解java和多线程中的Singleton类

c# - 为什么 .NET 4.0 对该数组的排序方式与 .NET 3.5 不同?

c# - 将 XML 结构解析(并保留)到 SQL Server 中

windows - 当我们安装或卸载 .msi 或 .exe 包时会发生什么?

java - 阻塞 HeapTaskDaemon 线程的 ANR