關於寄宿和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的具體功能:
一個進程上面運行一個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的玩法需要的時候再進一步深究。(話說回來,總有一種一輩子玩不到這個東西的感覺)