LoaderOptimizationAttribute的影响

时间:2011-04-25 21:02:35

标签: c# appdomain .net-assembly dynamic-loading appdomainsetup

我编写了一小段关于动态加载程序集和从这些程序集创建类实例的代码,包括可执行文件,要动态加载的测试库和用于将动态程序集加载到新{{1 }}。 Loader库由可执行文件和动态库引用。

Appdomain
  1. 我在//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; } } } 方法设置了LoaderOptimizationAttribute,但main()表示AppDomain.CurrentDomain.SetupInformation.LoaderOptimization.ToString();为什么?

  2. NotSpecifiedMultiDomain之间的差异对我来说并不是那么清楚。 MultiDomainHost只适用于GAC程序集吗?对于我更适合的情况?

  3. 根据this

      

    无法共享JIT编译的代码   装配到装载中的装配   上下文,使用LoadFrom方法   Assembly类,或从中加载   使用Load的重载的图像   指定字节数组的方法。

  4. 那么如何检测程序集是否加载域中性?怎么能保证我加载域中立?

1 个答案:

答案 0 :(得分:13)

如果使用NGen预编译程序集以加速应用程序的热启动,则此属性仅起作用。指定MultiDomainMultiDomainHost时,可以启用预编译(ngenned)程序集的使用。您可以使用 Process Explorer 验证这一点,您可以在其中查看已加载模块的列表。

如果您的应用程序包含多个共享程序集的可执行实例,那么这是最大的启动时间节省之一。这使.NET能够在进程之间共享代码页,从而节省实际内存(一个程序集只在物理内存中存在一次,但在一个或多个进程之间共享),并防止在每个进程中反复JITing相同的代码这需要花费时间,生成的代码效率稍低,因为它可以使用常规JIT进行编译,JIT可以使用更多动态数据来生成最有效的代码。

在您的示例中,您将程序集加载到位于托管堆中的字节数组中,并增加您的专用字节数。这使得无法在进程之间共享数据。只有在硬盘上具有对应物的只读页面才能在进程之间共享。这就是属性无效的原因。如果您在热启动性能的2倍之后,这就是您要寻找的属性。对于其他任何事情都没有用。

现在回到原来的问题:

  1. 已设置,但在调试器下启动应用程序时,将忽略此MultiDomain属性。当您在调试器之外启动它时,您将获得预期的结果。
  2. MultiDomainHost确实只对已签名的程序集启用AppDomain中立,其他所有程序都不会共享。
  3. 代码共享只能在预编译时进行。真正的问题是:如何检查程序集是否已预编译?我通过查看已加载模块的列表,使用 Process Explorer 来完成此操作。当我加载的程序集显示带有Native Image缓存和.ni扩展名的路径时,我确信预编译的图像正在使用。当您将单选按钮设置为本机图像以检查运行时未使用本机图像的原因时,也可以使用 fuslogvw 进行检查。