AppDomain隨記

一個進程可以包含多個線程
一個AppDomain可以創建多個線程
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),這個存儲區用來存儲這個hard thread對應的AppDomain的引用和對應的soft thread的引用
當hard thread穿越到另外一個AppDomain時,TLS中的這些引用頁會改變
Assembly不能單獨執行,必須被加載到AppDomain中,然後由AppDomain創建程序集中的對象

Assembly和AppDomain是多對多的關係,一個Assembly可以被多個AppDomain加載,一個AppDomain中可以加載多個Assembly

AppDomain引用到某個類型的時候,需要把相應的Assembly在AppDomain中初始化,因此,每個AppDomain都會單獨保持一個類的靜態變量
任何對象只能屬於一個AppDomain,被AppDomain所隔離,不同AppDomain之間的對象必須通過Proxy(reference type)或者Clone(value type)通信
引用類型需要繼承System.MarshalByRefObject才能被Marshal/UnMarshal(Proxy)
值類型需要設置Serializable屬性才能被Marshal/UnMarshal(Clone)

程序集分成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屬性可以設置三個不同的枚舉值,來設置針對前面說的三種程序集的代碼存放以及訪問方式。



1.SingleDomain,由於只啓動一個AppDomain,那麼code就被直接裝載到了AppDomain中,訪問靜態變量更快捷。
2.MultiDomain,所有的Assembly代碼是進程級別的,因此所有的AppDomain只訪問一份代碼。這大大減少了程序佔用的內存,但
是由於程序集的靜態變量仍然在各個AppDomain中,因此代碼訪問靜態變量需要先得到AppDomain的引用再進行轉換,速度會受到影響。
3.MultiDomainHost,只有GAC代碼是共享的,非GAC的Assembly依然會加載到被使用的AppDomain中,這樣提高了靜態變量的訪問速度,當然也增加了程序佔用的內存。
不管是哪種方式,mscorlib始終是process級別的,即只有一份mscorlib代碼在內存中。
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()來得到

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章