Эффект LoaderOptimizationAttribute

Я написал небольшую часть кода, касающуюся динамической загрузки сборок и создания экземпляров классов из этих сборок, включая исполняемый файл, тестовую библиотеку для динамической загрузки и библиотеку загрузчика для загрузки динамической сборки в новый Appdomain, Библиотека загрузчика ссылается как на исполняемый, так и на динамическую библиотеку.

//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(); говорит, что это NotSpecified Почему?

  • Различия между MultiDomain и MultiDomainHost мне не так понятны. Является ли MultiDomainHost только для сборок GAC? Для моей ситуации, которая более подходит?

  • Согласно this

    JIT-скомпилированный код нельзя использовать для сборок, загружаемых в нагрузку контекста, используя метод LoadFrom класс Ассамблеи или загруженный из изображения с использованием перегрузок нагрузки метод, который задает массивы байтов.

Итак, как я могу определить, загружена ли сборка без доменов или нет? Как можно гарантировать, что он загружен доменом-нейтральным?

Ответ 1

Этот атрибут имеет только эффект, если вы предварительно скомпилируете свои сборки с помощью NGen, чтобы ускорить теплый старт вашего приложения. Когда вы укажете MultiDomain или MultiDomainHost, вы включите использование предварительно скомпилированных (ngenned) сборок. Вы можете проверить это с помощью Проводника процессов, где вы можете посмотреть список загруженных модулей.

Это одно из самых больших хранителей времени запуска, если ваше приложение состоит из нескольких исполняемых экземпляров, которые совместно используют сборки. Это позволяет .NET совместно использовать кодовые страницы между процессами, которые, в свою очередь, сохраняют реальную память (одна сборка существует только один раз в физической памяти, но она разделяется между одним или несколькими процессами) и предотвращает повторение JIT-кода одного и того же кода в каждом процессе что требует времени за счет того, что сгенерированный код немного менее эффективен, поскольку он может быть скомпилирован с помощью обычного JIT, который может использовать более динамические данные для генерации наиболее эффективного кода.

В вашем примере вы загружаете сборку в массив байтов, который находится в управляемой куче, и увеличивает количество личных байтов. Это делает невозможным обмен данными между процессами. Только те страницы, которые имеют копию на вашем жестком диске, могут быть разделены между процессами. Вот почему атрибут не действует. Если вы после 2-го коэффициента тепловой загрузки, это атрибут, который вы искали. Для чего-либо еще это не имеет значения.

Теперь вернемся к исходному вопросу:

  • Он установлен, но когда вы запускаете приложение под отладчиком, этот атрибут MultiDomain игнорируется. Когда вы запустите его за пределами отладчика, вы получите ожидаемые результаты.
  • Да MultiDomainHost активирует нейтральность AppDomain только для подписанных сборок, все остальные не разделяются.
  • Обмен кодами может произойти только тогда, когда он предварительно скомпилирован. Реальный вопрос: как проверить, была ли сборка предварительно скомпилирована? Я делаю это с помощью Process Explorer, просматривая список загруженных модулей. Когда моя загруженная сборка появляется с пути к кешу Native Image и расширением .ni, я уверен, что прекомпилированное изображение используется. Вы также можете проверить это с помощью fuslogvw, когда вы установите переключатель на Native Images, чтобы проверить, почему встроенные изображения не использовались средой выполнения.