免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
應用程序域及Assembly.Unload 的相關問題
userphoto

2010.11.02

關注

Assembly.Unload

http://flier_lu.blogone.net/?id=2164751


    CLR 產品單元經理(Unit Manager) Jason Zander 在前幾天一篇文章 Why isn't there an Assembly.Unload method? 中解釋了為什么 CLR 中目前沒有實現類似 Win32 API 中 UnloadLibrary 函數功能的 Assembly.Unload 方法。
    他認為之所以要實現 Assembly.Unload 函數,主要是為了回收空間和更新版本兩類需求。前者在使用完 Assembly 后回收其占用資源,后者則卸載當前版本載入更新的版本。例如 ASP.NET 中對頁面用到的 Assembly 程序的動態(tài)更新就是一個很好的使用示例。但如果提供了 Assembly.Unload 函數會引發(fā)一些問題:

    1.為了包裝 CLR 中代碼所引用的代碼地址都是有效的,必須跟蹤諸如 GC 對象和 COM CCW 之類的特殊應用。否則會出現 Unload 一個 Assembly 后,還有 CLR 對象或 COM 組件使用到這個 Assembly 的代碼或數據地址,進而導致訪問異常。而為了避免這種錯誤進行的跟蹤,目前是在 AppDomain 一級進行的,如果要加入 Assembly.Unload 支持,則跟蹤的粒度必須降到 Assembly 一級,這雖然在技術上不是不能實現,但代價太大了。

    2.如果支持 Assembly.Unload 則必須跟蹤每個 Assembly 的代碼使用到的句柄和對現有托管代碼的引用。例如現在 JITer 在編譯方法時,生成代碼都在一個統(tǒng)一的區(qū)域,如果要支持卸載 Assembly 則必須對每個 Assembly 都進行獨立編譯。此外還有一些類似的資源使用問題,如果要分離跟蹤技術上雖然可行,但代價較大,特別是在諸如 WinCE 這類資源有限的系統(tǒng)上問題比較明顯。

    3.CLR 中支持跨 AppDomain 的 Assembly 載入優(yōu)化,也就是 domain neutral 的優(yōu)化,使得多個 AppDomain 可以共享一份代碼,加快載入速度。而目前 v1.0 和 v1.1 無法處理卸載 domain neutral 類型代碼。這也導致實現 Assembly.Unload 完整語義的困難性。

    基于上述問題, Jason Zander 推薦使用其他的設計方法來回避對此功能的使用。如 Junfeng Zhang 在其 BLog 上介紹的 AppDomain and Shadow Copy,就是 ASP.NET 解決類似問題的方法。

    在構造 AppDomain 時,通過 AppDomain.CreateDomain 方法的 AppDomainSetup 參數中 AppDomainSetup.ShadowCopyFiles 設置為 "true" 啟用 ShadowCopy 策略;然后設置 AppDomainSetup.ShadowCopyDirectories 為復制目標目錄;設置 AppDomainSetup.CachePath + AppDomainSetup.ApplicationName 指定緩存路徑和文件名。
    通過這種方法可以模擬 Assembly.Unload 的語義。實現上是將需要管理的 Assembly 載入到一個動態(tài)建立的 AppDomain 中,然后通過跨 AppDomain 的透明代理調用其功能,使用 AppDomain.Unload 實現 Assembly.Unload 語義的模擬。chornbe 給出了一個簡單的包裝類,具體代碼見文章末尾。
    
    這樣做雖然在語義上能夠基本上模擬,但存在很多問題和代價:
    
    1.性能:在 CLR 中,AppDomain 是類似操作系統(tǒng)進程的邏輯概念,跨 AppDomain 通訊就跟以前跨進程通訊一樣受到諸多限制。雖然通過透明代理對象能夠實現類似跨進程 COM 對象調用的功能,自動完成參數的 Marshaling 操作,但必須付出相當的代價。Dejan Jelovic給出的例子(Cross-AppDomain Calls are Extremely Slow)中,P4 1.7G 下只使用內建類型的調用大概需要 1ms。這對于某些需要被頻繁調用的函數來說代價實在太大了。如他提到實現一個繪圖的插件,在 OnPaint 里面畫 200 個點需要 200ms 的調用代價。雖然可以通過批量調用進行優(yōu)化,但跨 AppDomain 調用效率的懲罰是肯定無法逃脫的。好在據說 Whidbey 中,對跨 AppDomain 調用中的內建類型,可以做不 Marshal 的優(yōu)化,以至于達到比現有實現調用速度快 7 倍以上,...,我不知道該夸獎 Whidbey 實現的好呢,還是痛罵現有版本之爛,呵呵
    
    2.易用性:需要單獨卸載的 Assembly 中類型可能不支持 Marshal,此時就需要自行處理類型的管理。
    
    3.版本:在多個 AppDomain 中如何包裝版本載入的正確性。
    
    此外還有安全方面問題。對普通的 Assembly.Load 來說,載入的 Assembly 是運行在載入者的 evidence 下,而這絕對是一個安全隱患,可能遭受類似 unix 下面通過溢出以 root 權限讀寫文件的程序來改寫系統(tǒng)文件的類似攻擊。而單獨在一個 AppDomain 中載入 Assembly 就能夠單獨設置 CAS 權限,降低執(zhí)行權限。因為 CLR 架構下的四級權限控制機制,最細的粒度只能到 AppDomain。好在據說 Whidbey 會加入對使用不同 evidence 載入 Assembly 的支持。
    
    通過這些討論可以看到,Assembly.Unload 對于基于插件模型的程序來說,其語義的存在是很重要的。但在目前和近幾個版本來說,通過 AppDomain 來模擬其語義是比較合適的選擇,雖然要付出性能和易用性的問題,但能夠更大程度上控制功能和安全性等方面因素。長遠來說,Assembly.Unload 的實現是完全可行的,Java 中對類的卸載就是最好的例子,前面那些理由實際上都是工作量和復雜度方面的問題,并不存在無法解決的技術問題。


以下為引用:

// ObjectLoader.cs
using System;
using System.Reflection;
using System.Collections;

namespace Loader{

  /* contains assembly loader objects, stored in a hash
  * and keyed on the .dll file they represent. Each assembly loader
  * object can be referenced by the original name/path and is used to
  * load objects, returned as type Object. It is up to the calling class
  * to cast the object to the necessary type for consumption.
  * External interfaces are highly recommended!!
  * */
  public class ObjectLoader : IDisposable
  {
    // essentially creates a parallel-hash pair setup
    // one appDomain per loader
    protected Hashtable domains = new Hashtable();
    // one loader per assembly DLL
    protected Hashtable loaders = new Hashtable();

    public ObjectLoader() {/*...*/}

    public object GetObject( string dllName, string typeName, object[] constructorParms )
    {
      Loader.AssemblyLoader al = null;
      object o = null;

      try{
        al = (Loader.AssemblyLoader)loaders[ dllName ];
      } catch (Exception){}

      if( al == null )
      {
        AppDomainSetup setup = new AppDomainSetup();
        setup.ShadowCopyFiles = "true";

        AppDomain domain = AppDomain.CreateDomain( dllName, null, setup );

        domains.Add( dllName, domain );

        object[] parms = { dllName };
        // object[] parms = null;
        BindingFlags bindings = BindingFlags.CreateInstance | BindingFlags.Instance | BindingFlags.Public;

        try{
          al = (Loader.AssemblyLoader)domain.CreateInstanceFromAndUnwrap(
            "Loader.dll", "Loader.AssemblyLoader", true, bindings, null, parms, null, null, null);
        } catch (Exception){
          throw new AssemblyLoadFailureException();
        }

        if( al != null )
        {
          if( !loaders.ContainsKey( dllName ) )
          {
            loaders.Add( dllName, al );
          }
          else
          {
            throw new AssemblyAlreadyLoadedException();
          }
        }
        else
        {
          throw new AssemblyNotLoadedException();
        }
      }

      if( al != null )
      {
        o = al.GetObject( typeName, constructorParms );

        if( o != null && o is AssemblyNotLoadedException )
        {
          throw new AssemblyNotLoadedException();
        }

        if( o == null || o is ObjectLoadFailureException )
        {
          string msg = "Object could not be loaded. Check that type name " + typeName +
            " and constructor parameters are correct. Ensure that type name " + typeName +
            " exists in the assembly " + dllName + ".";

          throw new ObjectLoadFailureException( msg );
        }
      }
      return o;
    }

    public void Unload( string dllName )
    {
      if( domains.ContainsKey( dllName ) )
      {
        AppDomain domain = (AppDomain)domains[ dllName ];
        AppDomain.Unload( domain );
        domains.Remove( dllName );
      }
    }

    ~ObjectLoader()
    {
      dispose( false );
    }

    public void Dispose()
    {
      dispose( true );
    }

    private void dispose( bool disposing )
    {
      if( disposing )
      {
        loaders.Clear();

        foreach( object o in domains.Keys )
        {
          string dllName = o.ToString();
          Unload( dllName );
        }
        domains.Clear();
      }
    }
  }
}
 




以下為引用:

// Loader.cs
using System;
using System.Reflection;

namespace Loader {
  // container for assembly and exposes a GetObject function
  // to create a late-bound object for casting by the consumer
  // this class is meant to be contained in a separate appDomain
  // controlled by ObjectLoader class to allow for proper encapsulation
  // which enables proper shadow-copying functionality.
  internal class AssemblyLoader : MarshalByRefObject, IDisposable {

    #region class-level declarations
    private Assembly a = null;
    #endregion

    #region constructors and destructors
    public AssemblyLoader( string fullPath )
    {
      if( a == null )
      {
        a = Assembly.LoadFrom( fullPath );
      }
    }

    ~AssemblyLoader()
    {
      dispose( false );
    }

    public void Dispose()
    {
      dispose( true );
    }

    private void dispose( bool disposing )
    {
      if( disposing )
      {
        a = null;
        System.GC.Collect();
        System.GC.WaitForPendingFinalizers();
        System.GC.Collect( 0 );
      }
    }
    #endregion

    #region public functionality
    public object GetObject( string typename, object[] ctorParms )
    {
      BindingFlags flags = BindingFlags.CreateInstance | BindingFlags.Instance | BindingFlags.Public;

      object o = null
      ;
      if( a != null )
      {
        try
        {
          o = a.CreateInstance( typename, true, flags, null, ctorParms, null, null );
        }
        catch (Exception)
        {
          o = new ObjectLoadFailureException();
        }
      }
      else
      {
        o = new AssemblyNotLoadedException();
      }
      return o;
    }

    public object GetObject( string typename )
    {
      return GetObject( typename, null );
    }
    #endregion


  }
}
本站僅提供存儲服務,所有內容均由用戶發(fā)布,如發(fā)現有害或侵權內容,請點擊舉報
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
C++與C#有關對庫(動態(tài)庫dll,靜態(tài)庫.lib)文件的調用
淺析.Net下的AppDomain編程
如何從程序集中加載及卸載插件(上)
C#動態(tài)程序集的加載、創(chuàng)建實例、序列化與反序列化
有關System.Reflection.Assembly(反射的應用)
把C#程序(含多個Dll)合并成一個Exe的超簡單方法
更多類似文章 >>
生活服務
分享 收藏 導長圖 關注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點擊這里聯系客服!

聯系客服