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。

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