『框架设计(第2版)CLR Via C#』学习笔记——CLR寄宿
没办法,这本书写的太好了,我基本是照抄书的。(*^__^*) 嘻嘻……
我们知道编程人员一般把程序集的加载及反射和寄宿和应用程序域结合起来在一起使用。这四种技术一起使用使CLR成为一个功能更加丰富和强大的平台。
.NET Framework运行在Microsoft Windows平台之上,这就意味着.NET Framework肯定是用Windows可以理解的技术来构建的。首先体现在.NET Framework中所有的托管模块和程序集文件都必须使用Windows的可移植可执行(Portable Executable,PE)文件格式,也就是说它们或者必须是Windows EXE文件,或者必须是一个动态链接库(Dynamic Link Library,DLL)文件。
在开发CLR时,Microsoft实际上是将CLR作为一个COM服务器实现在一个DLL内。也就是说,Microsoft为CLR定义了一个标准的COM接口,并且为该接口和COM服务器分配了GUID(全球通有标识符)。安装.NET Framework时,表示CLR的COM服务器就像其他COM服务器一样被注册到Windows的注册表里了。如果想要了解有关这方面的信息,可以参考和.NET Framework的SDk一起发布的C++头文件MSCorEE.h。该头文件中定义了一些GUID和非托管的ICorRuntimeHost接口定义。
任何Windows应用程序都可以寄宿CLR。但是,我们不应该通过调用CoCreateInstance来创建CLR COM服务器的实例,相反,我们的非托管宿主应该调用CorBindToRuntimeEx函数或者另外一个相似的函数(它们的原型定义在MSCorEE.h文件中)。CorBindToRuntimeEx函数在MSCorEE.dll文件(通常位于C:\Windows\System32目录下)中实现。该DLL被称为“垫片”(shim),它的职责是判断创建何种版本的CLR,但它本身不包含CLR COM服务器。
一台机器可以安装多个版本的CLR,但是机器中只有一个版本的MSCorEE.dll文件(垫片),即机子上最新版本的CLR一起发布的MSCorEE.dll的版本。不过这也有例外,例如在64位版本的Windows,就有两个版本,一个版本是32位的x86版,另一个是64位的x64或者IA64版(取决于计算机的CPU的架构)。
CLR本身并不在MSCorEE.dll文件中实现,它在一个称为MSCorWks.dll文件中实现。文件MSCorWks.dll文件的位置在C:\Windows\Microsoft.Net\Framework\v(版本号)。
调用CorBindToRuntimeEx函数时,该函数的参数允许宿主指定它希望创建的CLR的版本,同时还可以指定一些其他设置项。CorBindToRuntimeEx函数除了使用宿主指定的版本信息,还可以自己搜索一些额外的信息(eg.机器安装了多少个CPU)来决定加载那个版本的CLR——也就是说,垫片不用加载宿主所请求的那个版本的CLR。
默认情况下,当托管可执行文件开始执行时,垫片会查看可执行文件,并提取当初生成好测试应用程序时所使用的CLR的版本信息。但是,应用程序可以通过在它的XML配置文件中设置requiredRuntime和SupportedRuntime两个条目来重写这个默认行为。
CorBindToRuntimeEx函数返回一个指向非托管接口ICLRRuntimeHost的指针。寄宿应用程序可以调用该接口中定义的方法来设置下述各项:
- 设置宿主管理器 告诉CLR宿主希望参与内存分配、线程调度或同步、程序集加载等相关的决定。宿主也可以声明它希望获得有关垃圾收集启动和停止以及特定操作超时的通知。
- 获得CLR管理器 告诉CLR组织使用某些类或者成员。另外,宿主可以分辨什么代码可以调试,什么代码不能调试,以及当某个特定事件(例如应用程序域的卸载、CLR停止或者堆栈溢出异常等)发生时宿主应调用哪个方法。
- 初始化并启动CLR。
- 加载程序集并执行程序集中的代码。
- 停止CLR,从而阻止任何托管代码在Windows中运行。
有许多原因可以解释寄宿CLR为何很有用。寄宿允许人呢和应用陈旭支持CLR特征以及可编程性,允许应用程序用托管代码编写(至少局部可以)。任何寄宿CLR的应用程序都可以为准备扩展应用陈旭的开发人员提供一些便利,这些便利包括以下几点:
- 可以用任意的编程语言编程。
- 代码被JIT编译,从而加快速度(与解析相对)。
- 代码使用垃圾收集,从而避免内存泄露和破坏。
- 代码在安全的“沙箱(sandbox)”中运行。
- 宿主不必担心提供一个丰富的开发开发环境。宿主可以使用现有的技术,包括:编程语言、编译器、编辑器、调试器、测评器等。
另外,当然,Windows进程完全不必加载CLR,只有需要在进程中执行托管代码时才加载CLR。一个Windows进程只可以加载一个版本的CLR,因此不可能在一个单独的进程中加载两个或者多个版本的CLR。如果一个宿主进程调用了CorBindToRuntimeEx函数多次,那么每次都会返回同一个ICLRRuntimeHost指针。
一旦CLR加载到Windows的进程,就永远不会被卸载,即使调用ICLRRuntimeHost接口上的AddRef方法和Release方法也没有用。要想卸载进程中的CLR,只能终止该进程,导致Windows清理该进程使用的所有资源。