gpt4 book ai didi

c# - LoaderOptimizationAttribute 的作用

转载 作者:可可西里 更新时间:2023-11-01 08:24:12 25 4
gpt4 key购买 nike

我已经写了一小段关于动态加载程序集和从这些程序集创建类实例的代码,包括一个可执行文件、一个要动态加载的测试库和一个将动态程序集加载到新 中的加载器库应用域。加载程序库被可执行文件和动态库引用。

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

  2. MultiDomainMultiDomainHost 之间的区别我不是很清楚。 MultiDomainHost 是否仅适用于 GAC 程序集?对于我的情况,哪种更合适?

  3. 根据 this

    JIT-compiled code cannot be shared for assemblies loaded into the load-from context, using the LoadFrom method of the Assembly class, or loaded from images using overloads of the Load method that specify byte arrays.

那么我如何检测程序集是否以域中立的方式加载?我如何确保它加载的是域中立的?

最佳答案

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

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

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

现在回到你原来的问题:

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

关于c# - LoaderOptimizationAttribute 的作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5783228/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com