CLR via C#讀書筆記 CLR寄宿和AppDomain

來源:互聯網
上載者:User

標籤:cache   啟動過程   通過   ocr   建立   cee   for   線程   pre   

寄宿

寄宿是指讓其他應用程式(Unmanaged 程式碼)使用CLR的能力,比如自己用C++開發的表單能建立CLR執行個體。

Managed 程式碼也能調用Unmanaged 程式碼


   
  1. [DllImport("kernel32.dll")]
  2. public static extern int WinExec(string exeName, int operType);

通常會調用win32 api,但是要查文檔才知道怎麼定義extern方法

CLR實際上被實現為COM伺服器,可以通過CoCreateInstanceCLRCreateInstance(推薦)建立CLR COM伺服器執行個體,而宿主就能使用CLR的東西。

CLRCreateInstanceMSCorEE.dll裡面(在安裝.Net Framework時被到系統目錄中),他的工作決定建立哪個版本的CLR(這個dll與.Net一起安裝,但卻是唯一的,安裝了多個版本的.Net電腦中這個dll總是最新版本)

無論是託管程式還是非託管程式,他們都會編譯成PE檔案(儲存程式的自描述資訊,比如入庫函數),而託管程式開始執行時會有一條JMP指令跳轉到MSCorEE.dll裡,通過MSCorEE.dll的PE檔案資訊找到這個_CorExeMain函數的入口地址,然後修改剛才的JMP指令要跳轉的地址,從而將控制跳轉到了_CorExeMain這個函數裡面去。隨後CLR被啟動,接著根據託管程式的CLR表頭找到入口地址,再跳轉進去,程式開始運行

AppDomain

程式集邏輯容器
有點像進程,提供的資料和代碼隔離,但建立的代價比真正建立進程小。

  • 不能訪問其他AppDomain建立的對象
  • 可卸載
  • 可單獨配置
    • 這些配置涉及搜尋路徑,版本繫結重新導向,載入程式集的方式
  • 可單獨保護
    • 有單獨的許可權集

  • CLR啟動時會建立一個預設的AppDomain
  • AppDomain中有個Loader堆,記錄該AppDomain建立以來訪問過了哪些類型(類型對象)
  • 頻繁被使用的類比如Object,它的類型對象會儲存在特殊的AppDomain中被其他AppDomain共用,代價是這個AppDomain永遠不會被卸載
  • 注意多個AppDomain是用同一個託管堆
跨程式域通訊

AppDomain的核心是隔離但是它還是提供了跨AppDomain訪問對象的方法

假設一個情景,在AppDomain A中去訪問AppDomain B的對象


  
  1. AppDomain appDomainB = AppDomain.CreateDomain("NewDomain");
  2. DemoClass obj;
  3. // 在新的應用程式定義域中建立對象
  4. obj = (DemoClass)appDomainB.CreateInstanceAndUnwrap("ClassLib", "ClassLib.DemoClass");

這裡會拋出異常:"ClassLib.DemoClass"未標記為可序列化

其實這個過程叫做按值封送,這個過程中會建立兩個對象,在AppDomain B中建立一個,然後序列化成位元組數組,傳給AppDomain A,再還原序列化成對象,這種做法要求DemoClass必須被打上可序列化特性。

還有一種封送方式叫按引用封送,這種方式要求DemoClass派生自MarshalByRefObject
還是用上面一樣的代碼,這個過程本質是建立了兩個對象,在AppDomain A中建立了個代理對象obj,AppDomainB也建立個對象(這是真正的對象),在B向A發送對象引用前會做以下操作:

  • 在AppDomain A的Loader堆中定義一個代理對象的類型對象(有與AppDomain B的ClassLib.DemoClass類的類型對象完全一樣的執行個體成員:方法,屬性,事件,但不包括執行個體欄位)
    • 實際上內部會通過代理類找到真正的對象,再用反射獲得欄位值
  • 定義代理類對象自己的執行個體欄位(儲存了那個AppDomain擁有真實的對象,以及如何找到他)

訪問對象時(這是個同步的過程),利用代理類的資訊,切換線程到B,獲得真正的對象,調用真正的方法

卸載AppDomain

通過AppDomain.Unload方法

過程:

  • 掛起執行Managed 程式碼的所有線程
  • 檢查與被卸載AppDomain有關係的線程,強迫它拋出異常ThreadAbortException
    • 如果拋出的異常沒被處理,異常會被CLR”吞噬”,線程終止,進程繼續執行
  • 找到所有建立的代理對象,給它們設定個flag,之後所有嘗試調用代理對象方法的操作都會拋異常
  • 強制啟動記憶體回收
  • 恢複剩餘線程
監視AppDomain

通過修改AppDomain的靜態屬性MonitoringEnabled為true來啟動監視,一旦啟動就不能關閉.
啟動後可以讀取下面4個屬性

  • MonitoringSurivedProcessMemorySize 當前CLR執行個體控制的所有AppDomain使用的位元組數
  • MonitoringTotalAllocatedMemorySize 已指派的位元組數
  • MonitoringSurvivedMemorySize 正則使用的位元組數
  • MonitoringTotalProcessorTime CPU佔用率
異常通知

通過給AppDomain.FirstChanceException事件註冊方法能在AppDomain拋異常時接到通知
這個時機是:在異常拋出後尋找catch塊前,FirstChanceException不能處理異常,AppDomain拋異常後會尋找catch,如果找不到則將異常拋給調用該AppDomain的AppDomain(中間有跨AppDomain傳遞),如果一直到線程棧頂都找不到catch塊,CLR將被終止

宿主如何使用AppDomain
  • winform,wpf,控制台都是自寄宿(self-host)的,在本文開頭說過,啟動exe時會載入MSCorEE.dll緊接著啟動CLR,初始化後再運行Main方法
  • Asp.Net中當使用者請求aspx時會被iis轉交給aspnet_isapi.dll(Unmanaged 程式碼),它負責啟動CLR,之後Asp.Net判斷該Web應用是否是第一次被請求,如果是則建立AppDomain,並以虛擬根目錄來標識。所以預設情況下,一個進程是可以跑多個網站(AppDomain)。
    • Asp.Net的一個亮點是允許不關閉伺服器的前提下動態更改網站代碼,當Asp.Net檢測出檔案被修改後則會卸載就的AppDomain並建立新的AppDomain(載入新的檔案),為了確保這一過程順利執行,Asp.Net使用了一個名為shadow copying1的功能
資料
  • 什麼是COM
  • CLR寄宿(上) MSCOREE.DLL
  • http://m.blog.csdn.net/zlbcdn/article/details/70195565
  • .Net,你為什麼會慢 (託管程式與非託管程式啟動過程)
  • <<.Net之美>>
TODO
  • .net Romoting(不同電腦,不同進程,跨AppDomain訪問對象技術)
  • SQLServer可以用Managed 程式碼寫預存程序?
  1. 在載入程式集時,先把程式集複製到Cache目錄下,再載入,這樣原程式集不會被鎖定。 ?

CLR via C#讀書筆記 CLR寄宿和AppDomain

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.