.NET Core 3.0 可卸载程序集原理简析
文章轉載授權級別:A ??????預計閱讀時間:8分鐘? ? ? 損失發(fā)量:不好統(tǒng)計
因為最近在群里被問到如何理解 .NET Core 3.0 可卸載程序集,所以就寫了這篇簡單的分析。
因為時間實在很少,這篇文章只簡單的羅列了相關的代碼,請配合官方說明文檔理解。
另外,書籍《.NET Core 底層原理》預計 11 月出版,出版社比較拖 :O。
Azulx:?昨晚下班群里問的農神,今早就出來了,這效率。?
鏈接
可卸載程序集的官方說明文檔如下:
https://github.com/dotnet/coreclr/blob/release/3.0/Documentation/design-docs/unloadability.md
程序集中的 IL 代碼經(jīng)過 JIT 編譯后,會儲存原生代碼在 LoaderAllocator 管理的 Code Heap 中,LoaderAllocator 的代碼地址如下:
https://github.com/dotnet/coreclr/blob/release/3.0/src/vm/loaderallocator.hpp
https://github.com/dotnet/coreclr/blob/release/3.0/src/vm/loaderallocator.cpp
https://github.com/dotnet/coreclr/blob/release/3.0/src/vm/loaderallocator.inl
負責分配原生代碼的是 CodeManager ,代碼地址如下:
https://github.com/dotnet/coreclr/blob/release/3.0/src/vm/codeman.h
https://github.com/dotnet/coreclr/blob/release/3.0/src/vm/codeman.cpp
GC 實現(xiàn)代碼如下:
https://raw.githubusercontent.com/dotnet/coreclr/release/3.0/src/gc/gc.cpp
對象頭 (MethodTable) 代碼如下:
https://github.com/dotnet/coreclr/blob/release/3.0/src/vm/methodtable.h
https://github.com/dotnet/coreclr/blob/release/3.0/src/vm/methodtable.inl
https://github.com/dotnet/coreclr/blob/release/3.0/src/vm/methodtable.cpp
AssemblyLoadContext 的代碼如下:
https://github.com/dotnet/coreclr/blob/release/3.0/src/System.Private.CoreLib/shared/System/Runtime/Loader/AssemblyLoadContext.cs??
分析
在 .NET Core 中我們不能新建 AppDomain (盡管有默認的幾個 AppDomain),程序集會通過 AssemblyLoadContext 管理。簡單的來說,AssemblyLoadContext 負責管理有依賴關系的一組程序集,例如程序集 A 依賴程序集 B,那么 A 和 B 需要使用同一個 AssemblyLoadContext 加載。每個 AssemblyLoadContext 都會關聯(lián)不同的 LoaderAllocator,也就是擁有不同的 Code Heap。
.NET Core 3.0 開始允許卸載用戶創(chuàng)建的 AssemblyLoadContext ,也就是回收 AssemblyLoadContext 為程序集分配的各種資源,包括 JIT 生成的原生代碼,PreCode,類型元數(shù)據(jù)等,流程大致如下:
用戶創(chuàng)建 AssemblyLoadContext (isCollectible = true)
用戶使用 AssemblyLoadContext 加載程序集 A
用戶使用 AssemblyLoadContext 加載程序集 B
用戶創(chuàng)建程序集 A 和 B 中的類型的實例,并執(zhí)行其中的方法
用戶卸載 AssemblyLoadContext
.NET Core 等待所有程序集 A 和 B 中的類型的實例都被回收后,釋放 AssemblyLoadContext 管理的 LoaderAllocator 分配的資源
可以參考下圖理解 (這是經(jīng)過簡化的流程,詳細流程可以看前面給出的官方說明文檔鏈接):
卸載 AssemblyLoadContext 時,取消對 LoaderAllocator 的關聯(lián)的代碼如下:
https://github.com/dotnet/coreclr/blob/release/3.0/src/binder/clrprivbinderassemblyloadcontext.cpp#L276??
GC 標記對象時,同時標記關聯(lián)的 LoaderAllocator 的代碼如下 (在 gc.cpp 里面):
#define go_through_object_cl(mt,o,size,parm,exp) { // 如果對象的 MethodTable 是由可回收的 AssemblyLoadContext 加載的 if (header(o)->Collectible()) { // 獲取關聯(lián)的 LoaderAllocator uint8_t* class_obj = get_class_object (o); uint8_t** parm = &class_obj; // 標記 LoaderAllocator (根據(jù) exp 的具體邏輯而定) do {exp} while (false); } // 如果對象包含引用類型的成員 if (header(o)->ContainsPointers()) { go_through_object_nostart(mt,o,size,parm,exp); } }//?調用?MethodTable::GetLoaderAllocatorObjectForGC #define get_class_object(i) GCToEEInterface::GetLoaderAllocatorObjectForGC((Object *)i)LoaderAllocator 被回收以后到釋放資源的相關代碼 (被回收之前的邏輯參考官方說明文檔):
https://github.com/dotnet/coreclr/blob/release/3.0/src/vm/loaderallocator.cpp#L520
https://github.com/dotnet/coreclr/blob/release/3.0/src/vm/appdomain.cpp#L857
https://github.com/dotnet/coreclr/blob/release/3.0/src/vm/appdomain.cpp#L817
https://github.com/dotnet/coreclr/blob/release/3.0/src/vm/appdomain.hpp#L3086
https://github.com/dotnet/coreclr/blob/release/3.0/src/vm/appdomain.cpp#L6240
https://github.com/dotnet/coreclr/blob/release/3.0/src/vm/appdomain.cpp#L6283
https://github.com/dotnet/coreclr/blob/release/3.0/src/vm/loaderallocator.cpp#L88
https://github.com/dotnet/coreclr/blob/release/3.0/src/vm/loaderallocator.cpp#L1301??
說明就到此為止了。你可能會奇怪為什么這篇文章沒有提到 Assembly 和 DomainAssembly ,這是因為它們在可卸載程序集的實現(xiàn)中并不重要,資源是通過 AssemblyLoadContext 關聯(lián)的 LoaderAllocator 統(tǒng)一分配和釋放的,與其說是可卸載程序集,不如說是可卸載程序集加載上下文 (AssemblyLoadContext)。?
https://github.com/dotnetcore
打賞一杯酒,削減三分愁。跟著我們走,脫發(fā)包你有。
組織打賞賬戶為檸檬的賬戶,請標注「NCC」,并留下您的名字,以下地址可查看收支明細:https://github.com/dotnetcore/Home/blob/master/Statement-of-Income-and-Expense.mdOpenNCC,專注.NET技術的公眾號https://www.dotnetcore.xyz微信ID:OpenNCC長按左側二維碼關注歡迎打賞組織
給予我們更多的支持
總結
以上是生活随笔為你收集整理的.NET Core 3.0 可卸载程序集原理简析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 干货|亲测有效的N倍学习效果笔记法
- 下一篇: .NetCore技术研究-Configu