找回密码
 立即注册
首页 业界区 安全 c# hosting 和 AppDomain

c# hosting 和 AppDomain

梭净挟 7 天前
前言

简单介绍一下hosting 和 appdomain。
这两个东西。
正文

我们经常听说寄宿,这个寄宿是什么东西呢? 也就是我们这里要介绍的hosting。
什么是寄宿呢?
想一个问题,一个c# 的exe 程序,为啥能够启动呢?我们记得dll中是il代码。
那么肯定要加载运行时对吧。
那么为什么叫做寄宿呢? 是因为所有的程序其实都可以加载clr。
就是将clr 寄宿到宿主中。
那么为什么clr能够寄宿到宿主中呢? 那肯定是有一套协议的吧,我们来看下这个流程。
首先我们安装clr的时候会在windows注册表中注册。
然后我们的clr其实是com服务器对吧,有一套公共的接口。
只要我们去实现对这些公共的接口,那么我们是不是就可以调用clr功能。
注册表的信息可能有下面这些:
1.png

但不要通过调用 CoCreateInstance 来创建 CLR COM 服务器的实例,相反,你的非托管宿主应该调用 MetaHost.h 文件中声明的 CLRCreateInstance 函数。CLRCreateInstance 函数在 MSCorEE.dll 文件中实现,该文件一般在C:\Windows\System32 目录中。这个 DLL 被人们亲切地称为“垫片”(shim),它的工作是决定创建哪个版本的CLR;垫片 DLL 本身不包含 CLR COM 服务器。
CLRCreateInstance 函数可返回一个 ICLRMetaHost 接口。宿主应用程序可调用这个接口的 GetRuntime 函数,指定宿主要创建的 CLR 的版本。然后,垫片将所需版本的 CLR 加载到宿主的进程中。
默认情况下,当一个托管的可执行文件启动时,垫片会检查可执行文件,提取当初生成和测试应用程序时使用的 CLR 的版本信息。但应用程序可以在它的 XML 配置文件中设置 requiredRuntime 和 supportedRuntime 这两项来覆盖该默认行为。
GetRuntime 函数返回指向非托管 ICLRRuntimeInfo 接口的指针。有了这个指针后,就可利用 GetInterface 方法获得 ICLRRuntimeHost 接口。宿主应用程序可调用该接口定义的方法来做下面这些事情。

  • 设置宿主管理器。告诉 CLR 宿主想参与涉及以下操作的决策:内存分配、线程调度/同步以及程序集加载等。宿主还可声明它想获得有关垃圾回收启动和停止以及特定操作超时的通知。
  • 获取 CLR 管理器。告诉 CLR 阻止使用某些类/成员。另外,宿主能分辨哪些代码可以调试,哪些不可以,以及当特定事件(例如 AppDomain 卸载、CLR停止或者堆栈溢出异常)发生时宿主应调用哪个方法。
  • 初始化并启动 CLR。
  • 加载程序集并执行其中的代码。
  • 停止 CLR,阻止任何更多的托管代码在 Windows 进程中运行。
也就是通过这一套协议呢,我们可以调用clr的东西了。
CLR 从进程中卸载的唯一途径就是终止进程,这会造成 Windows 清理进程使用的所有资源。
那么,那么,也就是说无论是java 还是 python或者其他语言,只要实现了clr的接口,那么就可以加载和调用clr。
也就是说,可以进行这个和c#代码进行交互了。
那么我们加载了clr,我们怎么运行我们的clr平台的代码呢?这就是说我们怎么完成我们的托管?
有点意思哈。
CLR COM 服务器初始化时会创建一个 AppDomain。AppDomain 是一组程序集的逻辑容器。 CLR 初始化时创建的第一个 AppDomain 称为“默认 AppDomain”,这个默认的 AppDomain 只有在 Windows 进程终止时才会被销毁。
也就是说,clr里面会创建一个appdomain。
2.png

那么是否只有一个appdomain呢? 这个也不是,可以有多个,正是因为有多个,所以呢,这个是可以做到一些很难做到的事情。

  • 一个 AppDomain 的代码不能直接访问另一个 AppDomain 的代码创建的对象
  • AppDomain 可以卸载
  • AppDomain 可以单独保护
  • AppDomain 可以单独配置
一个 Windows 进程,其中运行着一个 CLR COM 服务器。该 CLR 当前管理着两个 AppDomain(虽然在一个 Windows 进程中可以运行的 AppDomain 数量没有硬性限制)。每个 AppDomain 都有自己的 Loader 堆,每个 Loader 堆都记录了自 AppDomain 创建以来已访问过哪些类型。
3.webp

除此之外,每个 AppDomain 都加载了一些程序集。AppDomain #1(默认 AppDomain)有三个程序集:MyApp.exe,TypeLib.dll 和 System.dll。AppDomain #2 有两个程序集:Wintellect.dll 和 System.dll。
两个 AppDomain 都加载了 System.dll 程序集。如果这两个 AppDomain 都使用了来自 System.dll 的一个类型,那么两个 AppDomain 的 Loader 堆会为相同的类型分别分配一个类型对象;类型对象的内存不会由两个 AppDomain 共享。另外,一个 AppDomain 中的代码调用一个类型定义的方法时,方法的 IL 代码会进行 JIT 编译,生成的本机代码单独与每个 AppDomain 关联,而不是由调用它的所有 AppDomain 共享。
但 AppDomain 的设计宗旨就是提供隔离;CLR 要求在卸载某个 AppDomain 并释放其所有资源时不会影响到其他任何 AppDomain。复制 CLR 的数据结构才能保证这一点。另外,还保证多个 AppDomain 使用的类型在每个 AppDomain 中都有一组静态字段。
有的程序集本来就要由多个 AppDomain 使用。最典型的例子就是 MSCorLib.dll。该程序集包含了 System.Object,System.Int32 以及其他所有与 .NET Framework 密不可分的类型。CLR 初始化,该程序集会自动加载,而且所有 AppDomain 都共享该程序集中的类型。为了减少资源消耗,MSCorLib.dll 程序集以一种“AppDomain 中立”的方式加载。也就是说,针对以“AppDomain 中立”的方式加载的程序集,CLR 会为它们维护一个特殊的 Loader 堆。该 Loader 堆中的所有类型对象,以及为这些类型定义的方法 JIT 编译生成的所有本机代码,都会由进程中的所有 AppDomain 共享。遗憾的是,共享这些资源所获得的收益并不是没有代价的。这个代价就是,以 “AppDomain 中立”的方式加载的所有程序集永远不能卸载。要回收它们占用的资源,唯一的办法就是终止 Windows 进程,让 Windows 去回收资源。
那么在appDomain也是可以通信的,怎么通信呢?

  • 使用“按引用封送”进行跨 AppDomain 通信
  • 使用“按值封送”进行跨 AppDomain 通信
  • 使用不可封送的类型跨 AppDomain 通信
那么appdomain 有什么用呢?

  • web 服务器,每一个应用就是一个appdomain进行隔离,不用每一个都创建一个进程。
  • 插件,那么我们可以调用clr 去加载插件啥的,而插件崩溃又不影响默认的appdomain
  • 通过在新的应用程序域中加载更新的程序集,实现应用程序的热更新,避免重启应用程序。
  • 为不受信任的代码创建独立的应用程序域,限制其访问权限,提高应用程序的安全性。
  • 多租户应用程序:在同一个进程中为不同租户创建独立的应用程序域,实现租户间的隔离和安全性。
还有许多东西的。
反正我们隔离的时候想想这东西就行。

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册