CLR寄宿:流程如下所示: 1.調(diào)用MSCorEE.dll中的CLRCreateInstance函數(shù)來獲取一個ICLRMetaHost接口。 2.調(diào)用ICLRMetaHost接口的GetRuntime函數(shù)來指定宿主要創(chuàng)建的CLR版本,并獲取指向非托管ICLRRuntimeInfo接口的指針。 3.調(diào)用ICLRRuntimeInfo接口的GetInterface函數(shù)來獲取ICLRRuntimeHost接口。 4.調(diào)用ICLRRuntimeHost接口的相關(guān)函數(shù)來完成以下事情: 1>.設(shè)置宿主管理器,告訴CLR宿主想?yún)⑴c以下操作決策:內(nèi)存分配,線程調(diào)度,程序集加載等。 2>.獲取CLR管理器,告訴CLR阻止使用某些類或者成員。 3>.初始化并啟動CLR。 4>.加載程序集并執(zhí)行其中代碼。 5>.停止CLR,阻止任何更多的托管代碼在進程中的執(zhí)行。
AppDomain:是一組程序集的邏輯容器。具有以下特性: 1.一個AppDomain的代碼只能使用"按引用封送(marshal-by-reference)"或者"按值封送(marshal-by-value)"的語義來訪問另一個AppDomain的代碼創(chuàng)建的對象。 2.CLR不支持從AppDomain中卸載特定的程序集,但是可以卸載一個AppDomain。 3.AppDomain創(chuàng)建后會應(yīng)用一個權(quán)限集,它決定了向這個AppDomain中運行的程序集授予的最大權(quán)限。 4.AppDomain創(chuàng)建后會關(guān)聯(lián)一組配置設(shè)置,如:程序集加載方式,卷影復(fù)制以及加載器優(yōu)化等。 5.以"AppDomain中立"的方式加載的程序集,CLR會為它們維護一個特殊的loader堆。進程中所有的AppDomain都會共享該loader堆中的所有類型對象以及類型定義的函數(shù)等數(shù)據(jù)信息。
AppDomain通信:如下所示: 執(zhí)行過程如下所示: 1.使用Thread.GetDomain或者AppDomain.CurrentDomain函數(shù)來獲取目標(biāo)AppDomain。 2.使用AppDomain的CreateDomain函數(shù)來創(chuàng)建源AppDomain。 3.使用AppDomain的CreateInstanceAndUnwarp函數(shù)來創(chuàng)建指定程序集中指定類型的新對象。具體流程如下: 1>.線程從目標(biāo)AppDomain切換到源AppDomain。 2>.當(dāng)指定的程序集不存在時就拋出FileNotFoundException;否則就將該程序集加載到源AppDomain中。 3>.當(dāng)指定的程序集中不存在指定類型時就拋出TypeLoadException;否則就調(diào)用該類型的無參構(gòu)造函數(shù)來創(chuàng)建真實對象。 4>.當(dāng)指定類型是從MarshalByRefObject類型派生時就向目標(biāo)AppDomain的loader堆中定義一個代理類型;然后創(chuàng)建代理類型對象,并初始化它的字段來標(biāo)識源AppDomain以及真實對象。 5>.當(dāng)指定類型是從Object類型派生時,如果沒有[Serializable]標(biāo)簽的話就拋出SerializableException;否則就將真實對象的實例字段序列化成一個字節(jié)數(shù)組,然后將該字節(jié)數(shù)組從源AppDomain復(fù)制到目標(biāo)AppDomain,最后在目標(biāo)AppDomain中反序列化字節(jié)數(shù)組來創(chuàng)建真實對象的一個副本。 6>.線程從源AppDomain切換到目標(biāo)AppDomain。 4.操作代理類型對象時,實際上是操作源AppDomain中的真實對象。 5.操作副本對象時,實際上是操作目標(biāo)AppDomain中的副本對象。 注意事項如下所示: 1.由于CLR通過反射的方式調(diào)用FieldGetter以及FieldSetter函數(shù)來訪問MarshalByRefObject派生類型的實例字段,從而造成性能低下。 2.由于靜態(tài)類型會打破了AppDomain隔離的目標(biāo),所以不要在MarshalByRefObject派生類型中定義靜態(tài)成員。 3.可以重寫MarshalByRefObject類型的InitializeLifetimeService函數(shù)來設(shè)置該類型對象的租期。
卸載AppDomain:使用AppDomain的Unload函數(shù)來卸載AppDomain。流程如下所示: 1.當(dāng)調(diào)用Unload函數(shù)的線程就在"要卸載的AppDomain"中時,CLR會使該線程拋出ThreadAbortException;然后創(chuàng)建新的線程來嘗試卸載AppDomain。 2."要卸載的AppDomain"中的所有線程必須在10s內(nèi)離開。 3.CLR掛起進程中執(zhí)行托管代碼的所有線程。 4.CLR遍歷線程棧。任何棧上有"要卸載的AppDomain"時,CLR都會強迫對應(yīng)的線程拋出ThreadAbortException。 5.CLR遍歷堆。將"要卸載的AppDomain"所關(guān)聯(lián)的每個代理對象都設(shè)置一個標(biāo)志,此時在代理對象上調(diào)用函數(shù)就會拋出AppDomainUnloadException。 6.CLR強制垃圾回收"要卸載的AppDomain"所創(chuàng)建的任何對象的內(nèi)存。 7.CLR恢復(fù)剩余所有線程的執(zhí)行。 8.卸載AppDomain失敗時,線程將拋出CannotUnloadAppDomainException。
監(jiān)視AppDomain:用來監(jiān)視資源消耗情況。具有以下特性: 1.將AppDomain的MonitoringEnabled屬性設(shè)置為true,從而顯示地打開監(jiān)視;此時再將MonitoringEnabled屬性設(shè)置成false時就會拋出ArgumentException。 2.可以使用AppDomain的MonitoringSurvivedProcessMemorySize屬性來獲取所有AppDomain使用的字節(jié)數(shù)。 3.可以使用AppDomain的MonitoringTotalAllocatedMemorySize屬性來獲取特定AppDomain已分配的字節(jié)數(shù)。 4.可以使用AppDomain的MonitoringSurvivedMemorySize屬性來獲取特定AppDomain當(dāng)前正在使用的字節(jié)數(shù)。 5.可以使用AppDomain的MonitoringTotalProcessorTime屬性來獲取特定AppDomain的CPU占用率。
AppDomain異常通知:執(zhí)行流程如下: 1.CLR調(diào)用向拋出異常的AppDomain登記的所有FirstChanceException回調(diào)函數(shù)。 2.CLR查找棧上在同一個AppDomain中的任何catch塊。有一個catch塊能處理異常,則異常處理完成,將繼續(xù)正常執(zhí)行;否則CLR沿著棧向上來查找AppDomain,如果不存在AppDomain時就終止進程;否則就再次拋出同一個異常對象,并執(zhí)行流程1和流程2。
輔助函數(shù):如下所示: 1.Assembly.GetEntryAssembly:用來獲取具有Main函數(shù)的程序集。 2.RemotingService.IsTransparentProxy:用來判斷指定對象是否為代理對象。
其他要點:如下所示: 1.只有ControlThread標(biāo)志被設(shè)置成true的線程才能通過Thread的ResetAbort函數(shù)來阻止CLR自動向上傳遞ThreadAbortException。
|