CLR via C#:CLR寄宿和AppDomain

CLR寄宿:流程如下所示:
1.调用MSCorEE.dll中的CLRCreateInstance函数来获取一个ICLRMetaHost接口。
2.调用ICLRMetaHost接口的GetRuntime函数来指定宿主要创建的CLR版本,并获取指向非托管ICLRRuntimeInfo接口的指针。
3.调用ICLRRuntimeInfo接口的GetInterface函数来获取ICLRRuntimeHost接口。
4.调用ICLRRuntimeHost接口的相关函数来完成以下事情:
1>.设置宿主管理器,告诉CLR宿主想参与以下操作决策:内存分配,线程调度,程序集加载等。
2>.获取CLR管理器,告诉CLR阻止使用某些类或者成员。
3>.初始化并启动CLR。
4>.加载程序集并执行其中代码。
5>.停止CLR,阻止任何更多的托管代码在进程中的执行。

AppDomain:是一组程序集的逻辑容器。具有以下特性:
1.一个AppDomain的代码只能使用"按引用封送(marshal-by-reference)"或者"按值封送(marshal-by-value)"的语义来访问另一个AppDomain的代码创建的对象。
2.CLR不支持从AppDomain中卸载特定的程序集,但是可以卸载一个AppDomain。
3.AppDomain创建后会应用一个权限集,它决定了向这个AppDomain中运行的程序集授予的最大权限。
4.AppDomain创建后会关联一组配置设置,如:程序集加载方式,卷影复制以及加载器优化等。
5.以"AppDomain中立"的方式加载的程序集,CLR会为它们维护一个特殊的loader堆。进程中所有的AppDomain都会共享该loader堆中的所有类型对象以及类型定义的函数等数据信息。

AppDomain通信:如下所示:
执行过程如下所示:
1.使用Thread.GetDomain或者AppDomain.CurrentDomain函数来获取目标AppDomain。
2.使用AppDomain的CreateDomain函数来创建源AppDomain。
3.使用AppDomain的CreateInstanceAndUnwarp函数来创建指定程序集中指定类型的新对象。具体流程如下:
1>.线程从目标AppDomain切换到源AppDomain。
2>.当指定的程序集不存在时就抛出FileNotFoundException;否则就将该程序集加载到源AppDomain中。
3>.当指定的程序集中不存在指定类型时就抛出TypeLoadException;否则就调用该类型的无参构造函数来创建真实对象。
4>.当指定类型是从MarshalByRefObject类型派生时就向目标AppDomain的loader堆中定义一个代理类型;然后创建代理类型对象,并初始化它的字段来标识源AppDomain以及真实对象。
5>.当指定类型是从Object类型派生时,如果没有[Serializable]标签的话就抛出SerializableException;否则就将真实对象的实例字段序列化成一个字节数组,然后将该字节数组从源AppDomain复制到目标AppDomain,最后在目标AppDomain中反序列化字节数组来创建真实对象的一个副本。
6>.线程从源AppDomain切换到目标AppDomain。
4.操作代理类型对象时,实际上是操作源AppDomain中的真实对象。
5.操作副本对象时,实际上是操作目标AppDomain中的副本对象。
注意事项如下所示:
1.由于CLR通过反射的方式调用FieldGetter以及FieldSetter函数来访问MarshalByRefObject派生类型的实例字段,从而造成性能低下。
2.由于静态类型会打破了AppDomain隔离的目标,所以不要在MarshalByRefObject派生类型中定义静态成员。
3.可以重写MarshalByRefObject类型的InitializeLifetimeService函数来设置该类型对象的租期。

卸载AppDomain:使用AppDomain的Unload函数来卸载AppDomain。流程如下所示:
1.当调用Unload函数的线程就在"要卸载的AppDomain"中时,CLR会使该线程抛出ThreadAbortException;然后创建新的线程来尝试卸载AppDomain。
2."要卸载的AppDomain"中的所有线程必须在10s内离开。
3.CLR挂起进程中执行托管代码的所有线程。
4.CLR遍历线程栈。任何栈上有"要卸载的AppDomain"时,CLR都会强迫对应的线程抛出ThreadAbortException。
5.CLR遍历堆。将"要卸载的AppDomain"所关联的每个代理对象都设置一个标志,此时在代理对象上调用函数就会抛出AppDomainUnloadException。
6.CLR强制垃圾回收"要卸载的AppDomain"所创建的任何对象的内存。
7.CLR恢复剩余所有线程的执行。
8.卸载AppDomain失败时,线程将抛出CannotUnloadAppDomainException。

监视AppDomain:用来监视资源消耗情况。具有以下特性:
1.将AppDomain的MonitoringEnabled属性设置为true,从而显示地打开监视;此时再将MonitoringEnabled属性设置成false时就会抛出ArgumentException。
2.可以使用AppDomain的MonitoringSurvivedProcessMemorySize属性来获取所有AppDomain使用的字节数。
3.可以使用AppDomain的MonitoringTotalAllocatedMemorySize属性来获取特定AppDomain已分配的字节数。
4.可以使用AppDomain的MonitoringSurvivedMemorySize属性来获取特定AppDomain当前正在使用的字节数。
5.可以使用AppDomain的MonitoringTotalProcessorTime属性来获取特定AppDomain的CPU占用率。

AppDomain异常通知:执行流程如下:
1.CLR调用向抛出异常的AppDomain登记的所有FirstChanceException回调函数。
2.CLR查找栈上在同一个AppDomain中的任何catch块。有一个catch块能处理异常,则异常处理完成,将继续正常执行;否则CLR沿着栈向上来查找AppDomain,如果不存在AppDomain时就终止进程;否则就再次抛出同一个异常对象,并执行流程1和流程2。

辅助函数:如下所示:
1.Assembly.GetEntryAssembly:用来获取具有Main函数的程序集。
2.RemotingService.IsTransparentProxy:用来判断指定对象是否为代理对象。

其他要点:如下所示:
1.只有ControlThread标志被设置成true的线程才能通过Thread的ResetAbort函数来阻止CLR自动向上传递ThreadAbortException。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章