2011-04-25 11 views
11

He escrito un pequeño fragmento de código sobre la carga dinámica de ensamblajes y la creación de instancias de clase a partir de esos ensamblados, incluido un ejecutable, una lib de prueba para cargar dinámicamente y una biblioteca de cargadores para cargar ensamblaje dinámico en un nuevo Appdomain. Los archivos ejecutables y la biblioteca dinámica hacen referencia a la biblioteca Loader.Efecto de LoaderOptimizationAttribute

//executable 
[System.STAThreadAttribute()] 
[System.LoaderOptimization(LoaderOptimization.MultiDomain)] 
static void Main(string[] args) 
{  
    AppDomainSetup domainSetup = new AppDomainSetup() 
    { 
     ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase, 
     ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile, 
     ApplicationName = AppDomain.CurrentDomain.SetupInformation.ApplicationName, 
     LoaderOptimization = LoaderOptimization.MultiDomain 
    }; 
    AppDomain childDomain = AppDomain.CreateDomain("MyDomain", null, domainSetup); 
    Console.WriteLine(AppDomain.CurrentDomain.SetupInformation.LoaderOptimization.ToString()); 
    Console.WriteLine(childDomain.SetupInformation.LoaderOptimization.ToString()); 

    byte[] assembly = null; 
    string assemblyName = "CSTestLib"; 

    using (FileStream fs = new FileStream(assemblyName+".dll",FileMode.Open)) 
    { 
     byte[] byt = new byte[fs.Length]; 
     fs.Read(byt,0,(int)fs.Length); 
     assembly = byt;   
    } 

    object[] pararmeters = {assemblyName,assembly}; 
    string LoaderAssemblyName = typeof(AssemblyLoader).Assembly.FullName; 
    string LoaderClassName = typeof(AssemblyLoader).FullName; 
    AssemblyLoader assloader = (AssemblyLoader)childDomain.CreateInstanceAndUnwrap(LoaderAssemblyName,LoaderClassName , true, BindingFlags.CreateInstance, null, parameters, null, null); 


    object obj = assloader.Load("CSTestLib.Class1"); 
    object obj2 = assloader.Load("CSTestLib.Class2"); 

    AppDomain.Unload(childDomain); 

    Console.ReadKey(); 
} 

//Dynamic Lib 
using System; 


namespace CSTestLib 
{ 
    public class Class1 :MarshalByRefObject 
    { 
     public Class1() { } 
    } 



    public class Class2 : MarshalByRefObject 
    { 
     public Class2() { } 
    } 
} 

//Loader Library 


using System; 

namespace LoaderLibrary 
{ 
    public class AssemblyLoader : MarshalByRefObject 
    { 
     string assemblyName; 
     public AssemblyLoader(string assName, byte[] ass) 
     { 
      assemblyName = assName; 
      AppDomain.CurrentDomain.Load(ass); 
      Console.WriteLine(AppDomain.CurrentDomain.FriendlyName + " " + AppDomain.CurrentDomain.SetupInformation.LoaderOptimization.ToString()); 
     } 

     public object Load(string className) 
     { 
      object ret = null; 
      try 
      { 
       ret = AppDomain.CurrentDomain.CreateInstanceAndUnwrap(assemblyName, className); 
      } 
      catch (System.Exception ex) 
      { 
       Console.WriteLine(ex.Message); 
      } 
      return ret; 
     } 
    } 
} 
  1. Aquí me puse LoaderOptimizationAttribute en main() método, pero AppDomain.CurrentDomain.SetupInformation.LoaderOptimization.ToString(); dice que es NotSpecified ¿Por qué?

  2. Las diferencias entre MultiDomain y MultiDomainHost no son tan claras para mí. ¿Es MultiDomainHost solo para ensambles GAC? Para mi situación, ¿cuál es más adecuada?

  3. Según this

    código JIT-compilado no puede ser compartido por ensamblados cargados en la carga de contexto, utilizando el método LoadFrom de la clase de ensamblado, o carga desde imágenes utilizando sobrecargas del método Load que especifica arrays de bytes.

Entonces, ¿cómo puedo detectar si un ensamblado se carga de dominio neutral o no? ¿Cómo puedo asegurar que esté cargado de dominio neutral?

Respuesta

11

Este atributo solo tiene un efecto si precompila sus ensamblajes con NGen para acelerar un inicio en caliente de su aplicación. Cuando especifica MultiDomain o MultiDomainHost, habilita el uso de ensamblados precompilados (ngenned). Puede verificar esto con Process Explorer donde puede ver la lista de módulos cargados.

Este es uno de los mayores ahorradores de tiempo de inicio si su aplicación consiste en varias instancias ejecutables que comparten ensamblajes. Esto permite que .NET comparta las páginas de códigos entre procesos, lo que a su vez ahorra memoria real (un ensamblaje existe solo una vez en la memoria física pero se comparte entre uno o más procesos) y evita que JIT repita el mismo código una y otra vez en cada proceso lo cual lleva tiempo a costa de que el código generado sea un poco menos eficiente, ya que podría ser cuando se compilaría con el JIT regular que puede usar datos más dinámicos para generar el código más eficiente.

En su ejemplo, carga el conjunto en una matriz de bytes que se encuentra en el montón administrado y aumenta su recuento de bytes privados. Esto hace que sea imposible compartir datos entre procesos. Solo las páginas de solo lectura que tienen una contraparte en su disco duro se pueden compartir entre procesos. Esta es la razón por la cual el atributo no tiene efecto. Si buscas un factor 2 de rendimiento de inicio cálido, este es el atributo que estabas buscando. Para cualquier otra cosa, no es relevante.

Ahora, de regreso a su pregunta original:

  1. Se fija pero cuando se inicia su aplicación bajo un depurador se ignora este atributo MultiDomain. Cuando lo inicie fuera de un depurador obtendrá los resultados esperados.
  2. MultiDomainHost habilita AppDomain neutralidad solo para montajes firmados, todos los demás no se comparten.
  3. El intercambio de código solo puede ocurrir cuando se precompila. La verdadera pregunta es: ¿cómo verificar si el ensamblaje está precompilado? Lo hago con Process Explorer mirando la lista de módulos cargados. Cuando mi ensamblaje cargado aparece con una ruta al caché de imagen nativa y una extensión .ni, estoy seguro de que se está utilizando la imagen precompilada. También puede verificar esto con fuslogvw cuando establece el botón de opción en Imágenes nativas para comprobar por qué el motor de ejecución no utilizó imágenes nativas.
+0

Me parece que el atributo realmente tiene un efecto. Ejecutar con depurador adjunto devuelve 'NotSpecified' ... ejecutando sin depurador devuelve' MultiDomain' ... Tal vez alguien puede confirmar eso. – Matthias