程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 【C#進階系列】22 CLR寄宿和AppDomain,

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

編輯:C#入門知識

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


關於寄宿和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堆。

主要步驟:

任何時候都只會有一個線程來調用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的玩法需要的時候再進一步深究。(話說回來,總有一種一輩子玩不到這個東西的感覺)

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved