標籤:
什麼是AppDomain?
我們都知道windows進程,它起到應用程式隔離的作用,帶來的好處是,當某個進程發生錯誤的時候,不會影響其他的進程,系統也不會受到影響。但是,建立windows進程的代價是很大的。.net推出AppDomain的作用也是隔離,如果能確保應用程式都是安全的程式碼(managed code),那麼appdomain其實就可以起到進程的作用。每個appdomain裡有自己的堆,負責自己內部對象的建立和銷毀,對象一般不能誇appdomain訪問。
當應用程式啟動,CLR載入後,會建立一個appdomain(預設的,它知道進程結束才會unload),程式集會在此appdomain中載入,運行。
Appdomain,程式集,進程的關係如所示:
這裡有個問題,即同樣的assembly會在不同的appdomain中使用,會造成資源的浪費,所以出現了domain-neutral assemblies,也就是說,這些assemblies與appdomain無關,CLR負責管理,對象的建立,銷毀都由CLR負責,當然,它們也只有等到CLR結束,也就是進程結束時才能unload。
跨AppDomain訪問對象
CLR Via C#書中第22章的例子,很好的解釋了如何跨appdomain對象訪問。
它會建一個新的appdomain,在這裡會建立(返回)3種類型的對象,1個是繼承自MarshaByRefObject類型的對象,1個是標註了[Serializable]的類型的對象,另一個是普通類型對象,對應有3個#demo。
#demo1
在新的appdomain中動態建立繼承自MarshaByRefObject類型的對象,然後在預設的appdomain中使用它的方法:
(1) 在新appdomain中create的對象,返回給原appdomain,實際上返回給原appdomain的是一個代理,也就是說mbrt變數指向的是一個proxy,而非新appdomain中的instance,所以IsTransparentProxy返回true。
(2) 在代理上執行方法,顯然是在遠程執行。
(3) 當新的appdomain卸載後,代理找不到原始對象,拋異常。
#demo2
在新的appdomain中動態建立標有[Serializable]的類型的對象,然後再預設的appdomain中使用
(1) 在新的appdomain建立的,返回原appdomain的,不會是代理,而是新appdomain中建立的對象的copy,在跨appdomain邊界的時候序列化成位元組流,回到原appdomain時,還原序列化回來的,所以IsTransparentProxy返回false。
(2) 由於mbvt指向的對象不是代理對象,所以在本地(本appdomain)執行。
(3) 由於在本地執行,所以儘管新的appdomain被unload了,仍然可以繼續執行。
#demo3
在新的appdomain中動態建立普通類型對象,既沒有繼承自MarshalByRefObject,也沒有標註[Serializable],然後再預設的appdomain中使用,這個時候,由於新appdomain發現,既不能按Marshal by ref封送,就按Marshal by value封送,但是卻不能序列化,所以只有跑序列化失敗的異常了:
結論:跨appdomain對象訪問有2種方式:by ref, by value,
(1) by ref要求對象繼承自MarshalByRefObject,並且在目的appdomain中使用的是代理。
(2) by value要求對象標註[Serializable],即能被序列化,那麼在目的appdomain中,使用的就是原對象的副本了。
.NET跨AppDomain訪問對象