Эффект LoaderOptimizationAttribute - PullRequest
       43

Эффект LoaderOptimizationAttribute

12 голосов
/ 26 апреля 2011

Я написал небольшой фрагмент кода, касающийся динамической загрузки сборок и создания экземпляров классов из этих сборок, включая исполняемый файл, тестовую библиотеку для динамической загрузки и библиотеку загрузчика для загрузки динамической сборки в новую 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;
        }
    }
}
  1. Здесь я устанавливаю LoaderOptimizationAttribute для main() метода, но AppDomain.CurrentDomain.SetupInformation.LoaderOptimization.ToString(); говорит, что это NotSpecified Почему?

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

  3. Согласно этот

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

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

1 Ответ

13 голосов
/ 26 апреля 2011

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

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

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

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

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