本章主要讨论了两个概念:Hosting和AppDomains。Hosting允许任何应用程序利用CLR的特性;AppDomain是进程中的一个逻辑区域,一个进程可以加载多个AppDomain,一个AppDomain中可以加载多个Assembly,AppDomain还可以被卸载。AppDomain可以为插件应用程序等提供很好的隔离性和安全性。首先解释了什么是CLR Hosting,什么是AppDomain,如何加载卸载监视AppDomain,然后讲了宿主怎样使用AppDomain,最后讲了高级的宿主控制方法以及如何写出健壮的宿主应用程序。
CLR Hosting
- Assembly和Module的关系:Assembly至少有一个Module(通常是一个),Module没有装箱单(Manifest)元数据,VS IDE不能直接生成Module以及多个Module的Assembly,但是csc编译器可以通过/t[arget]: module输出Module,缺省扩展名是.netmodule,编译器可以通过/addmodule附加到目标上。参考:CLR Via C# 3rd 阅读摘要 -- Chapter 2 - Building, Packaging, Deploying, and Administering Applications and Types
- CLR被设计成COM服务器组件包含在一个DLL(MSCorWrks.dll(1.0, 1.1, 2.0)/Clr.dll(4.0))中;
- MetaHost.h头文件中定义了CLR COM的GUIDs以及非托管的ICLRMetaHost接口;
- 任何Windows应用程序都可以托管CLR,但是你不能通过调用CoCreateInstance创建CLR COM Server的实例;
- 你可以通过调用MetaHost.h中的CLRCreateInstance(实现在MSCorEE.dll中)来创建CLR COM Server;
- .NET Framework 3.0, 3.5装载的是2.0的CLR;
- CLRCreateInstance返回一个ICLRMetaHost的接口,托管应用程序可以调用该接口的GetRuntime函数,指定你希望创建的CLR版本;
- 任何应用都可以托管CLR的好处:
- 多语言编程,编程语言无关;
- 代码可以使用JIT编译来提高速度;
- 代码可以使用垃圾收集器避免内存泄露和破坏;
- 代码可以运行在安全沙箱中;
- 不同担心开发环境,可以使用现有的技术:语言,编译器,编辑器,调试器,分析器,等等。
- 如何定制CLR?书籍:《Customizing the Microsoft .NET Framework Common Language Runtime》;
- 在.NET 4.0框架开始支持在一个Windows进程中同时加载2.0和4.0的CLR。
AppDomains
- AppDomain的目的就是为了隔离;
- AppDomain的特性:
- 一个AppDomain中创建的对象不能直接被其他的AppDomain访问,要跨AppDomain访问对象,必须采用marshal-by-reference或者marshal-by-value语义;
- AppDomains可以卸载;
- AppDomains可以有独立的安全性;
- AppDomains可以分别配置。
- CreateProcess Win32函数非常慢,Windows请求大量的内存来虚拟化进程地址空间;
- Windows托管AppDomains的进程模型:
- 一些程序集希望被多个AppDomains使用,比如MSCorLib.dll,以Domain-Neutral方式加载的程序集不能被卸载,除非CLR卸载;
- 怎样跨AppDomain边界访问对象?
- 通过使用Marshal-by-Reference跨AppDomain通信。
- 继承自MarshalByRefObject的类型应该避免定义任何静态成员;
- 租约管理:当一个代理对象创建后,CLR保持该对象存活5分钟。
- 通过使用Marshal-by-Value跨AppDomain通信。
- MarshalByValType没有继承自MarshalByRefObject,所以CLR不能定义一个代理类型直接创建它的实例;
- 当装载程序集时,CLR使用目标AppDomain的策略和配置。
- 通过使用Non-Marshalable类型跨AppDomain通信。
- 没有继承自MarshalByRefObject,虽然不能创建代理对象,但是如果标记有[Serializable],CLR可以序列化对象到一个字节数组,通过该字节数组来跨AppDomain边界通信;
- System.String就是没有继承自MarshalByRefObject,但是有[Serializable]属性标记。
- 因为一个Windows进程中可以装载多个AppDomains,一个线程可以在一个AppDomain中执行代码然后再到另外一个AppDomain中执行;
- 当一个AppDomain创建时,可以设定一个友好名称。
AppDomain Unloading
- AppDomain.Unload静态方法可以卸载一个AppDomain;
- CLR如何卸载AppDomain:
- CLR挂起执行托管代码进程中的所有线程;
- CLR检查所有的线程栈看当前卸载的AppDomain中哪些线程正在执行代码或者有可能返回到代码中的某些点。CLR强制这些线程在他们的线程栈上抛出ThreadAbortException。CLR在这些情形下并不会立即终止执行代码:catch/finally块、类构造器、CER、非托管代码中;
- 当上一步中发现的所有线程离开了AppDomain,CLR巡视堆并在每一个引用到卸载的AppDomain创建的真实对象的代理对象设置标记。如果有代码现在调用这些失效的代理对象上的方法,会抛出AppDomainUnloadedException异常;
- CLR强制垃圾收集器工作;
- CLR唤醒所有剩余的线程继续运行。
- 如果在卸载AppDomain的过程中调用AppDomain.Unload方法时,CLR会创建另外一个线程尝试卸载AppDomain。之前的卸载线程会被强制抛出ThreadAbortException。
AppDomain Monitoring
- AppDomain监视会招致额外的开销,必须显式的设置AppDomain.MonitoringEnabled静态属性来打开监视;
- MonitoringSurvivedProcessMemorySize、MonitoringTotalAllocatedMemorySize、MonitoringSurvivedMemorySize、MonitoringTotalProcessorTime;
AppDomain First-Chance Exception Notifications
- AppDomain.FirstChanceException事件;
- CLR如何处理一个异常:
- 当异常第一次抛出时,CLR调用注册的FirstChanceException事件的回调方法;
- 然后,CLR查找同一个AppDomain中的栈上的catch块。如果catch块处理了异常,正常继续。;
- 否则CLR沿着Appdomain的栈再次抛出同样的异常(在序列化/反序列化之后)。这里抛出的是一个新异常,所以CLR调用FirstChanceException事件的回调方法;
- 继续直至到达线程栈的顶端。到这里,如果异常没有被任何代码处理,CLR终止整个进程。
How Hosts Use AppDomains
- 可执行的应用程序:
- 控制台程序、NT服务程序、Windows窗体程序、WPF程序,可以自我宿主的应用程序;
- 调用System.Environment.Exit方法,首先会调用托管堆上的所有对象的Finalize方法,然后调用Win32的ExitFunction方法。
- SilverLight RIA应用程序:
- SilverLight CLR(CoreClr.dll),每一个页面上的SilverLight控件运行在各自的AppDomain中。
- ASP.NET WebForm和XML Web服务程序:
- 如果客户端请求一个不同的Web应用程序,ASP.NET告诉CLR创建一个新的AppDomain。这个新的AppDomain通常创建在同一个工作者进程中;
- Shadow Copying:当一个磁盘上的Web站点的文件改变后,ASP.NET会检测到,接着卸载老的版本(当最后一个工作中的请求完成后),然后创建一个新的AppDomain,然后装载新的版本。
- Microsoft Sql Server:
- Sql Server允许使用托管代码来开发存储过程。这意味着可以使用强类型,并且可以经过JIT编译后执行来取代解释执行。
- 你自己假想的情形。
Advanced Host Control
- 使用托管代码管理CLR,System.AppDomainManager;
- 宿主应用程序如何理解线程返回?
本章小结
本章主要讨论了两个概念:Hosting和AppDomains。Hosting允许任何应用程序利用CLR的特性;AppDomain是进程中的一个逻辑区域,一个进程可以加载多个AppDomain,一个AppDomain中可以加载多个Assembly,AppDomain还可以被卸载。AppDomain可以为插件应用程序等提供很好的隔离性和安全性。首先解释了什么是CLR Hosting,什么是AppDomain,如何加载卸载监视AppDomain,然后讲了宿主怎样使用AppDomain,最后讲了高级的宿主控制方法以及如何写出健壮的宿主应用程序。