【C#進階系列】22 CLR寄宿和AppDomain

來源:互聯網
上載者:User

標籤:

關於寄宿和AppDomain

微軟開發CLR時,將它實現成包含在一個DLL中的COM伺服器。

任何Windows應用程式都能寄宿(容納)CLR。(簡單來講,就是CLR在一個DLL中,通過引用這個DLL,可以實現包含CLR)

CLR COM伺服器初始化會建立一個預設AppDomain,這個AppDomain只有在進程終結時才會被銷毀。

然而宿主程式還可以要求CLR建立額外的AppDomain。

因為建立進程開銷很大,並且需要大量記憶體來虛擬化進程的地址空間。

所以人們就像可不可以在一個進程上運行多個程式呢。

於是就在進程上寄宿CLR,併除了AppDomain的概念。AppDomain是為了提供隔離而設計的。

當然原因不止如此,寄宿為應用程式提供了自訂和可擴充性的能力,然而這會導致一些惡意dll去破壞應用程式的資料結構和代碼,還能利用安全上下文來訪問本來無權訪問的資源。

CLR的AppDomain可以解決這個問題,允許第三方的不受信任的代碼在現有進程中運行,而CLR保證資料結構、代碼和安全上下文不被濫用和破壞

AppDomain,看名字就知道:應用程式定義域。

以下為AppDomain的具體功能:

  • 一個AppDomain的代碼不能訪問另一個AppDomain的代碼建立的對象。這樣就將兩個AppDomain隔離開來,這種隔離使AppDomain很容易在進程中卸載,不會影響其它AppDomain正在啟動並執行代碼。
  • AppDomain可以卸載。(前面提到過,預設的第一個AppDomain是不能卸載的)
  • AppDomian可以單獨保護。(每個AppDomain都會有自己的許可權集)
  • AppDomain可以單獨配置。(每個AppDomain都會有自己的配置設定,主要影響CLR在AppDomain中的載入方式。涉及搜尋路徑、版本繫結重新導向、卷影複製以及載入器最佳化)

一個進程上面運行一個CLR COM伺服器,然後該CLR管理多個AppDomain,每個AppDomain可以有自己獨立的程式。有的程式集是可以在AppDomain中共用的,比如MSCorLib.dll這種與.NET密不可分的類型,在CLR初始化時會被自動載入,有自己專屬的loader堆去維護類型對象,且作為"AppDomain"中立的方式為所有AppDomain共用。

跨越AppDomain邊界訪問對象

前面講到AppDomain就是為了隔離而設計的,且一個AppDomain的代碼不能訪問另一個AppDomain的代碼。

然而要去做到也不是沒有辦法,為了實現兩個AppDomain之間的通訊。

按照AppDomain通訊可以將類型分為三種:按引用封送類型,按值封送類型,完全不能封送的類型。

進程中可以有多個線程和多個AppDomain,然而它們不是一一對應的。

雖然一個線程一次只能執行一個AppDomain中的代碼,但是一個線程可以執行一個AppDomain的代碼後再去執行另一個AppDomain的代碼,並且還可以查看自己在哪個AppDomain中。

然而這裡由於感覺用不到關係,而且有點小複雜,所以就只領會了中心思想:

按引用封送:實際上就是AppDomain比如B傳給另一個AppDomain比如A一個引用對象b,當執行b的函數時,實際上是線程又切回了B,調用完後再切回A。

按值封送:這個實際上就是將一個AppDomain中的對象序列化然後放到另一個AppDomain進行還原序列化中。

卸載AppDomain

調用靜態方法AppDomain.Unload即可。

卸載AppDomain會卸載其中的所有程式集,釋放loader堆。

主要步驟:

  1. CLR掛起進程中執行過Managed 程式碼的所有線程
  2. 查看那些線程正在執行要卸載的AppDomain中的代碼,有就強迫對應的線程拋出一個ThreadAbortException(線程中止異常)並恢複執行線程,這將導致執行遇到的所有的finally塊以清理資源。如果沒有代碼捕捉到這個異常,那麼finally就不會執行,但是線程會終止,但進程可繼續運行。(其它所有未處理的異常我們在前面講過會終止進程,而這裡只會終止這個線程.
  3. 執行完第二步,所有的線程都會離開此AppDomain,CLR進入前面記憶體回收類似的標記階段,標記垃圾。
  4. CLR強制執行記憶體回收,這些對象的Finalize方法被調用來正確清理佔用的資源。
  5. CLR恢複所有線程的執行。

任何時候都只會有一個線程來調用Unload方法,不會有多個線程同時調用。

宿主如何使用AppDomain

控制台UI應用程式,NT Service應用程式,Windows表單應用程式和WPF應用程式都是自寄宿(即自己容納CLR)的應用程式。

它們都有託管exe檔案,託管exe檔案初始化進程後,會載入“墊片”(即MSCorEE.dll),墊片檢查應用程式集的CLR頭資訊,決定載入哪個版本的CLR到進程中,CLR載入完後再次檢查CLR頭去茶砸後Main函數,然後調用該方法後程式才算真正啟動起來。

再舉一個例子,就拿ASP.NET來說,用戶端請求一個Web應用程式時,如果是第一次請求,那麼就ASP.NET要求CLR建立新的AppDomain,每個Web應用程式根據虛擬根目錄來標識,然後讓CLR將包含應用程式所公開類型的程式集載入到新的AppDomain中,建立執行個體,並調用其中方法。如果不是第一次請求就不會建立新的AppDomain。然而如果用戶端請求不同的Web應用程式,也會建立新的AppDomain。貌似就說的是IIS裡的那些不同的網站。

 

小總結:

到這一步,還是打算講一下自己對這個東西的理解。

對於.NET的世界而言,都是在一個進程之上載入CLR(CLR COM伺服器),然後在這個CLR上再載入不同的AppDomain。

對於我們平常寫的那些簡單用.net建立的程式如控制台程式,實際上也是在一個託管exe上再載入CLR,而此時會載入了預設的一個AppDomain。此exe可以作為一個宿主去載入更多的AppDomain,然而這就需要自己手動去載入了。

而對於那些不是.NET的非託管應用程式,也是可以載入CLR,而此時也會載入了預設的一個AppDomain,實際上它也可以作為一個宿主去載入更多的AppDomain。

可能有偏差,還望指正!

PS:

本章內容只擇其精要寫了一下,具體的AppDomain的玩法需要的時候再進一步深究。(話說回來,總有一種一輩子玩不到這個東西的感覺)

【C#進階系列】22 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.