當我從 .NET 生成一個新執行緒時到底發生了什麼?
當我在 .NET 中生成一個新執行緒時,我想了解幕後究竟發生了什麼,如下所示:
Thread t = new Thread(DoWork); //I am not interested in DoWork per se t.Start();1、CLR和Windows核心中創建了哪些執行緒相關的對象?
為什麼需要這些對象?
x86、x64 Windows 上分配了多少託管/非託管記憶體(堆和棧)?
更新
我正在尋找諸如託管執行緒對象之類的對象,我假設它是t,但也許還有其他一些其他託管對象;核心執行緒對象,使用者執行緒環境塊等。
非常感謝!
Win32 和核心記憶體分配
我不確定 .NET 部分是如何工作的,但如果執行時確實決定使用作業系統創建一個真正的執行緒,它最終會呼叫 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 地址空間,但即使這個限制也可以允許在單個程序中使用數百個地址空間而不會耗盡空間。
如果設計使用的作業系統執行緒多於系統中的 CPU 數量,則應該對其進行審查。具有執行緒池的工作隊列和具有使用者模式調度的輕量級執行緒(使用纖程或其他庫的實現)應該能夠處理多執行緒而不需要過多的作業系統執行緒,從而使執行緒的記憶體成本變得不重要。