CLR寄宿

作者:追风剑情 发布于:2020-10-28 9:55 分类:C#

公共语言运行库 (common language runtime,CLR) 是托管代码执行核心中的引擎。

      .NET Framework在Windows平台的顶部运行。这意味着.NET Framework必须用Windows能理解的技术来构建。首先,所有托管模块和程序集文件都必须使用Windows PE文件格式,而且要么是Windows EXE文件,要么是DLL文件。

      开发CLR时,Microsoft实际是把它实现成包含在一个DLL中的COM服务器。也就是说Microsoft为CLR定义了一个标准的COM接口,并为该接口和COM服务器分配了GUID。安装.NET Framework时,代表CLR的COM服务器和其他COM服务器一样在Windows注册表中注册。要了解这方面的更多信息,可参考与.NET Framework SDK一起发布的C++头文件MetaHost.h。该头文件中定义了GUID和非托管ICLRMetaHost接口。

      任何Windows应用程序都能寄宿(容纳)CLR。但不要通过调用CoCreateInstance来创建CLR COM服务器的实例,相反,你的非托管宿主应该调用MetaHost.h文件中声明的CLRCreateInstance函数。CLRCreateInstance函数在MSCorEE.dll文件中实现,该文件一般在C:\Windows\System32目录中。这个DLL被人们亲切地称为“垫片”(shim),它的工作是决定创建哪个版本的CLR;垫片DLL本身不包含CLR COM服务器。

① 使用64位Windows实际会安装两个版本的MSCorEE.dll文件。一个是32位x86版本,在C:\Windows\System32目录中;另一个是64位x64或IA64版本(取决于计算机的CPU架构),在C:\Windows\SysWOW64目录中。

      一台机器可安装多个版本的CLR,但只有一个版本的MSCorEE.dll文件(垫片)。机器上安装的MSCorEE.dll是与机器上安装的最新版本的CLR一起发布的那个版本。所以,该版本的MSCorEE.dll知道如何查找机器上的老版本CLR。

      包含实际CLR代码的文件的名称在不同版本的CLR中是不同的。版本1.0,1.1和2.0的CLR代码在MSCorWks.dll文件中;版本4则在Clr.dll文件中。由于一台机器可能安装多个版本的CLR,所以这些文件安装到不同的目录,如下所示:

  • 版本1.0在C:\Windows\Microsoft.Net\Framework\v1.0.3705中。
  • 版本1.1在C:\Windows\Microsoft.Net\Framework\v1.0.4322中。
  • 版本2.0在C:\Windows\Microsoft.Net\Frmework\v2.0.50727中。
  • 版本4在C:\Windows\Microsoft.NET\Framework\v4.0.30319中。

② 注意,.NET Framework 3.0和3.5是与CLR2.0一起发布的。我没有显示.NET Framework 3.0和3.5的目录,因为CLR DLL是从v2.0.50727目录加载的。

      CLRCreateInstance函数可返回一个ICLRMetaHost接口。宿主应用程序可调用这个接口的GetRuntime函数,指定宿主要创建的CLR的版本。然后,垫片将所需版本的CLR加载到宿主的进程中。

      默认情况下,当一个托管的可执行文件启动时,垫片会检查可执行文件,提取当初生成和测试应用程序时使用的CLR的版本信息。但应用程序可以在它的XML配置文件中设置requiredRuntime和supportedRuntime这两项来覆盖该默认行为。

      GetRuntime函数返回指向非托管ICLRRuntimeInfo接口的指针。有了这个指针后,就可利用GetInterface方法获得ICLRRuntimeHost接口。宿主应用程序可调用该接口定义的方法来做下面这些事情:

  • 设置宿主管理器。告诉CLR宿主想参与涉及以下操作的决策:内存分配、线程调度/同步以及程序集加载等。宿主还可声明它想获得有关垃圾回收启动和停止以及特定操作超时的通知。
  • 获取CLR管理器。告诉CLR阻止使用某些类/成员。另外,宿主能分辨哪些代码可以调试,哪些不可以,以及当特定事件(例如AppDomain卸载、CLR停止或者堆栈溢出异常)发生时宿主应调用哪个方法。
  • 初始化并启动CLR。
  • 加载程序集并执行其中的代码。
  • 停止CLR,阻止任何更多的托管代码在Windows进程中执行。
注意  Windows进程完全可以不加载CLR,只有在进程中执行托管代码时才进行加载。在.NET Framework 4之前,CLR只允许它的一个实例寄宿在Windows进程中。换言之,在一个进程中,要么不包含任何CLR,要么只能包含CLR v1.0,CLR v1.1或者CLR 2.0之一。每进程仅一个版本的CLR显然过于局限。例如,这样Microsoft Office Outlook就不能加载为不同版本的.NET Framework生成和测试的两个加载项了。
但是,随着.NET Framework 4的发布,Microsoft支持在一个Windows进程中同时加载CLR v2.0和v4.0,为.NET Framework 2.0和4.0写的不同组件能同时运行,不会出现任何兼容性问题。这是一个令人激动的功能,因为它极大扩展了.NET Framework组件的应用场合。可利用ClrVer.exe工具检查给定的进程加载的是哪个(哪些)版本的CLR。
一个CLR加载到Windows进程之后,便永远不能卸载;在ICLRRuntimeHost接口上调用AddRef和Release方法是没有作用的。CLR从进程中卸载的唯一途径就是终止进程,这会造成Windows清理进程使用的所有资源。


标签: C#

Powered by emlog  蜀ICP备18021003号-1   sitemap

川公网安备 51019002001593号