.Net AppDomain詳解(一)

來源:互聯網
上載者:User

標籤:color   serial   odi   multi   如何擷取   host   停止   center   對比   

AppDomain是CLR的運行單元,它可以載入Assembly、建立對象以及執行程式。
AppDomain是CLR實現代碼隔離的基本機制。每一個AppDomain可以單獨運行、停止;每個AppDomain有自己預設的異常處理;一個AppDomain的運行失敗不會影響到其他的AppDomain。CLR在被CLR Host(windows shell or InternetExplorer or SQL Server)載入後,要建立一個預設的AppDomain,程式的進入點(Main方法)就是在這個預設的AppDomain中執行。  1.AppDomain vs 進程
AppDomain被建立在進程中,一個進程內可以有多個AppDomain。一個AppDomain只能屬於一個進程。 2.AppDomain vs 線程其實兩者本來沒什麼好對比的。AppDomain是個靜態概念,只是限定了對象的邊界;線程是個動態概念,它可以運行在不同的AppDomain。一個AppDomain內可以建立多個線程,但是不能限定這些線程只能在本AppDomain內執行代碼。CLR中的System.Threading.Thread對象其實是個soft thread,它並不能被作業系統識別;作業系統能識別的是hard thread。一個soft thread只屬於一個AppDomain,穿越AppDomain的是hard thread。當hard thread訪問到某個AppDomain時,一個AppDomain就會為之產生一個soft thread。hard thread有thread local storage(TLS),這個儲存區被CLR用來儲存這個hard thread當前對應的AppDomain引用以及softthread引用。當一個hard thread穿越到另外一個AppDomain時,TLS中的這些引用也會改變。
當然這個說法很可能是和CLR的實現相關的。  3.AppDomain vs Assembly
Assembly是.Net程式的基本部署單元,它可以為CLR提供用於識別類型的中繼資料等等。Assembly不能單獨執行,它必須被載入到AppDomain中,然後由AppDomain建立程式集中的對象。一個Assembly可以被多個AppDomain載入,一個AppDomain可以載入多個Assembly。每個AppDomain引用到某個類型的時候需要把相應的assembly在各自的AppDomain中初始化。因此,每個AppDomain會單獨保持一個類的靜態變數。  4.AppDomain vs 對象
任何對象只能屬於一個AppDomain。AppDomain用來隔離對象,不同AppDomain之間的對象必須通過Proxy(reference type)或者Clone(value type)通訊。參考型別需要繼承System.MarshalByRefObject才能被Marshal/UnMarshal(Proxy)。
實值型別需要設定Serializable屬性才能被Marshal/UnMarshal(Clone)。  5.AppDomain vs Assembly Code
AppDomain和程式集的原始碼是什麼關係呢?每個程式集的代碼會分別裝載到各個AppDomain中?
首先我們要把程式集分3類
1.mscorlib,這是每個.net程式都要引用到的程式集。
2.GAC,這個是強命名的公用程式集,可以被所有的.net程式引用。
3.Assembly not in GAC,這是普通的assembly,可以不是強命名,不放到GAC中。啟動CLR,進入entry point時可以設定LoaderOptimization屬性:[LoaderOptimization(LoaderOptimization.MultiDomain]
static void Main()
{...}LoaderOptimization屬性可以設定三個不同的枚舉值,來設定針對前面說的三種程式集的代碼存放以及訪問方式。LoaderOptimization Enumeration/Attribute
Value Expected Domains in Process Each Domain Expected to Run ... Code for MSCORLIB Code for Assemblies in GAC Code for Assemblies not in GAC
SingleDomain One N/A Per-process Per-domain Per-domain
MultiDomain Many Same Program Per-process Per-process Per-process
MultiDomainHost Many Different Programs Per-process Per-process Per-domain

1.SingleDomain,由於只啟動一個AppDomain,那麼code就被直接裝載到了AppDomain中,訪問靜態變數更快捷。2.MultiDomain,所有的Assembly代碼是進程層級的,因此所有的AppDomain只訪問一份代碼。這大大減少了程式佔用的記憶體,但是由於程式集的靜態變數仍然在各個AppDomain中,因此代碼訪問靜態變數需要先得到AppDomain的引用再進行轉換,速度會受到影響。3.MultiDomainHost,只有GAC代碼是共用的,非GAC的Assembly依然會載入到被使用的AppDomain中,這樣提高了靜態變數的訪問速度,當然也增加了程式佔用的記憶體。  不管是哪種方式,mscorlib始終是process層級的,即只有一份mscorlib代碼在記憶體中。C#中動態載入和卸載DLL

在C++中載入和卸載DLL是一件很容易的事,LoadLibrary和FreeLibrary讓你能夠輕易的在程式中載入DLL,然後在任何地方 卸載。在C#中我們也能使用Assembly.LoadFile實現動態載入DLL,但是當你試圖卸載時,你會很驚訝的發現Assembly沒有提供任何 卸載的方法。這是由於Managed 程式碼的自動記憶體回收機制會做這件事情,所以C#不提供釋放資源的函數,一切由記憶體回收來做。 

這引發了一個問題,用Assembly載入的DLL可能只在程式結束的時候才會被釋放,這也意味著在程式運行期間無法更新被載入的DLL。而這個功能在某 些程式設計時是非常必要的,考慮你正在用反射機制寫一個查看DLL中所有函數詳細資料的程式,程式提供一個菜單讓使用者可以選擇DLL檔案,這時就需要讓程 序能夠卸載DLL,否則一旦使用者重新得到新版本DLL時,必須要重新啟動程式,重新選擇載入DLL檔案,這樣的設計是使用者無法忍受的。 

C#也提供了實現動態卸載DLL的方法,通過AppDomain來實現。AppDomain是一個獨立執行應用程式的環境,當AppDomain被卸載的 時候,在該環境中的所有資源也將被回收。關於AppDomain的詳細資料參考MSDN。下面是使用AppDomain實現動態卸載DLL的代碼, 

using System; using System.Collections.Generic; using System.Text; using System.Threading; using System.Reflection; namespace UnloadDll { class Program { static void Main(string[] args) { string callingDomainName = AppDomain.CurrentDomain.FriendlyName;//Thread.GetDomain().FriendlyName; Console.WriteLine(callingDomainName); AppDomain ad = AppDomain.CreateDomain("DLL Unload test"); ProxyObject obj = (ProxyObject)ad.CreateInstanceFromAndUnwrap(@"UnloadDll.exe", "UnloadDll.ProxyObject"); obj.LoadAssembly(); obj.Invoke("TestDll.Class1", "Test", "It‘s a test"); AppDomain.Unload(ad); obj = null; Console.ReadLine(); } } class ProxyObject : MarshalByRefObject { Assembly assembly = null; public void LoadAssembly() { assembly = Assembly.LoadFile(@"TestDLL.dll"); } public bool Invoke(string fullClassName, string methodName, params Object[] args) { if(assembly == null) return false; Type tp = assembly.GetType(fullClassName); if (tp == null) return false; MethodInfo method = tp.GetMethod(methodName); if (method == null) return false; Object obj = Activator.CreateInstance(tp); method.Invoke(obj, args); return true; } } } 


注意: 

1. 要想讓一個對象能夠穿過AppDomain邊界,必須要繼承MarshalByRefObject類,否則無法被其他AppDomain使用。 

2. 每個線程都有一個預設的AppDomain,可以通過Thread.GetDomain()來得到

 

更多:

C#如何測試代碼已耗用時間

C# 訪問操作註冊表整理

C#中如何擷取系統內容變數等

http://www.cnblogs.com/HopeGi/p/6422357.html

http://www.cnblogs.com/awpatp/archive/2009/11/24/1609570.html

.Net 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.