.NET Core 3.0 可卸载程序集原理简析


风晓
风晓 2023-12-31 10:22:36 50231 赞同 0 反对 0
分类: 资源
这篇文章只简单的罗列了相关的代码,请配合官方说明文档理解。

分析

在 .NET Core 中我们不能新建 AppDomain (尽管有默认的几个 AppDomain),程序集会通过 AssemblyLoadContext 管理。简单的来说,AssemblyLoadContext 负责管理有依赖关系的一组程序集,例如程序集 A 依赖程序集 B,那么 A 和 B 需要使用同一个 AssemblyLoadContext 加载。每个 AssemblyLoadContext 都会关联不同的 LoaderAllocator,也就是拥有不同的 Code Heap。

.NET Core 3.0 开始允许卸载用户创建的 AssemblyLoadContext ,也就是回收 AssemblyLoadContext 为程序集分配的各种资源,包括 JIT 生成的原生代码,PreCode,类型元数据等,流程大致如下:

  • 用户创建 AssemblyLoadContext (isCollectible = true)
  • 用户使用 AssemblyLoadContext 加载程序集 A
  • 用户使用 AssemblyLoadContext 加载程序集 B
  • 用户创建程序集 A 和 B 中的类型的实例,并执行其中的方法
  • 用户卸载 AssemblyLoadContext
  • .NET Core 等待所有程序集 A 和 B 中的类型的实例都被回收后,释放 AssemblyLoadContext 管理的 LoaderAllocator 分配的资源

可以参考下图理解 (这是经过简化的流程,详细流程可以看前面给出的官方说明文档链接):

卸载 AssemblyLoadContext 时,取消对 LoaderAllocator 的关联的代码如下:

https://github.com/dotnet/coreclr/blob/release/3.0/src/binder/clrprivbinderassemblyloadcontext.cpp#L276

GC 标记对象时,同时标记关联的 LoaderAllocator 的代码如下 (在 gc.cpp 里面):

#define go_through_object_cl(mt,o,size,parm,exp)                            \
{                                                                           \
    // 如果对象的 MethodTable 是由可回收的 AssemblyLoadContext 加载的
    if (header(o)->Collectible())                                           \
    {                                                                       \
        // 获取关联的 LoaderAllocator
        uint8_t* class_obj = get_class_object (o);                             \
        uint8_t** parm = &class_obj;                                           \
        // 标记 LoaderAllocator (根据 exp 的具体逻辑而定)
        do {exp} while (false);                                             \
    }                                                                       \
    // 如果对象包含引用类型的成员
    if (header(o)->ContainsPointers())                                      \
    {                                                                       \
        go_through_object_nostart(mt,o,size,parm,exp);                      \
    }                                                                       \
}
CPP 复制 全屏
// 调用 MethodTable::GetLoaderAllocatorObjectForGC
#define get_class_object(i) GCToEEInterface::GetLoaderAllocatorObjectForGC((Object *)i)

如果您发现该资源为电子书等存在侵权的资源或对该资源描述不正确等,可点击“私信”按钮向作者进行反馈;如作者无回复可进行平台仲裁,我们会在第一时间进行处理!

评价 0 条
风晓L1
粉丝 1 资源 2038 + 关注 私信
最近热门资源
银河麒麟桌面操作系统备份用户数据  129
统信桌面专业版【全盘安装UOS系统】介绍  125
银河麒麟桌面操作系统安装佳能打印机驱动方法  116
银河麒麟桌面操作系统 V10-SP1用户密码修改  106
麒麟系统连接打印机常见问题及解决方法  13
最近下载排行榜
银河麒麟桌面操作系统备份用户数据 0
统信桌面专业版【全盘安装UOS系统】介绍 0
银河麒麟桌面操作系统安装佳能打印机驱动方法 0
银河麒麟桌面操作系统 V10-SP1用户密码修改 0
麒麟系统连接打印机常见问题及解决方法 0
作者收入月榜
1

prtyaa 收益393.62元

2

zlj141319 收益218元

3

1843880570 收益214.2元

4

IT-feng 收益210.13元

5

风晓 收益208.24元

6

777 收益172.71元

7

Fhawking 收益106.6元

8

信创来了 收益105.84元

9

克里斯蒂亚诺诺 收益91.08元

10

技术-小陈 收益79.5元

请使用微信扫码

加入交流群

请使用微信扫一扫!