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