问题 LoaderOptimizationAttribute的影响


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

//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. 我在这里设定 LoaderOptimizationAttribute 上 main() 方法但是 AppDomain.CurrentDomain.SetupInformation.LoaderOptimization.ToString(); 说它是 NotSpecified 为什么?

  2. 之间的区别 MultiDomain 和 MultiDomainHost 我不太清楚。是 MultiDomainHost 仅适用于GAC组件?对于我的情况哪个更合适?

  3. 根据 这个 

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

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


5072
2018-04-25 21:02


起源



答案:


如果使用预编译程序集,则此属性仅起作用 NGEN 加快应用程序的热启动。当你指定 MultiDomain 要么 MultiDomainHost 您启用预编译(ngenned)程序集的使用。你可以用这个验证 Process Explorer 您可以在其中查看已加载模块的列表。

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

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

现在回到你原来的问题:

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

11
2018-04-25 21:17



在我看来,该属性实际上有效。运行调试器附件返回 NotSpecified...没有调试器返回运行 MultiDomain......也许有人可以证实这一点。 - Matthias


答案:


如果使用预编译程序集,则此属性仅起作用 NGEN 加快应用程序的热启动。当你指定 MultiDomain 要么 MultiDomainHost 您启用预编译(ngenned)程序集的使用。你可以用这个验证 Process Explorer 您可以在其中查看已加载模块的列表。

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

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

现在回到你原来的问题:

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

11
2018-04-25 21:17



在我看来,该属性实际上有效。运行调试器附件返回 NotSpecified...没有调试器返回运行 MultiDomain......也许有人可以证实这一点。 - Matthias