Как библиотеки DLL загружаются в CLR? - PullRequest
13 голосов
/ 03 июня 2010

Я всегда предполагал, что CLR загружает все необходимые библиотеки DLL при запуске домена приложения. Тем не менее, я написал пример, который заставляет меня усомниться в этом предположении. Я запускаю свое приложение и проверяю, сколько модулей загружено.

Process[] ObjModulesList;
ProcessModuleCollection ObjModulesOrig;

//Get all modules inside the process
ObjModulesList = Process.GetProcessesByName("MyProcessName");
// Populate the module collection.
ObjModulesOrig = ObjModulesList[0].Modules;

Console.WriteLine(ObjModulesOrig.Count.ToString());

Затем я повторяю тот же самый код, и мой счет отличается. Дополнительная библиотека DLL: C: \ WINNT \ system32 \ version.dll.

Я действительно не понимаю, почему счет будет другим.

Может, кто-нибудь уточнит, что делает CLR и как он загружает эти вещи, и по какой логике это делает?

Ответы [ 4 ]

23 голосов
/ 03 июня 2010

Следующая копия с Дон Бокса отлично Essential .Net . (доступно здесь )
(и, imho, должен иметь любой профессиональный разработчик .Net)

Загрузчик CLR

Загрузчик CLR отвечает за загрузку и инициализацию сборок, модулей, ресурсов и типов. Загрузчик CLR загружает и инициализирует настолько мало, насколько это возможно. В отличие от загрузчика Win32, загрузчик CLR не разрешает и автоматически загружает подчиненные модули (или сборки). Скорее, подчиненные части загружаются по требованию, только если они действительно необходимы (как с функцией отложенной загрузки Visual C ++ 6.0). Это не только ускоряет время инициализации программы, но и уменьшает количество ресурсов, потребляемых работающей программой. В CLR загрузка обычно запускается компилятором JIT (Just in Time), основанным на типах. Когда JIT-компилятор пытается преобразовать тело метода из CIL в машинный код, ему требуется доступ к определению типа объявленного типа, а также к определениям типа для полей типа. Кроме того, JIT-компилятору также необходим доступ к определениям типов, используемым любыми локальными переменными или параметрами JIT-компилируемого метода. Загрузка типа подразумевает загрузку как сборки, так и модуля, который содержит определение типа. Эта политика загрузки типов (и сборок и модулей) по требованию означает, что части программы, которые не используются, никогда не заносятся в память. Это также означает, что работающее приложение часто будет видеть новые сборки и модули, загруженные с течением времени, так как типы, содержащиеся в этих файлах, необходимы во время выполнения. Если это не то поведение, которое вам нужно, у вас есть два варианта. Один из них - просто объявить скрытые статические поля типов, которые вы хотите явно взаимодействовать с загрузчиком.

Загрузчик обычно выполняет свою работу неявно от вашего имени. Разработчики могут явно взаимодействовать с загрузчиком через загрузчик сборок. Загрузчик сборок предоставляется разработчикам через статический метод LoadFrom в классе System.Reflection.Assembly. Этот метод принимает строку CODEBASE, которая может быть либо путем к файловой системе, либо унифицированным указателем ресурса (URL), который идентифицирует модуль, содержащий манифест сборки. Если указанный файл не может быть найден, загрузчик выдаст исключение System.FileNotFoundException. Если указанный файл может быть найден, но не является модулем CLR, содержащим манифест сборки, загрузчик сгенерирует исключение System.BadImageFormatException. Наконец, если CODEBASE - это URL-адрес, который использует схему, отличную от file:, вызывающая сторона должна иметь права доступа WebPermission, иначе выдается исключение System.SecurityException. Кроме того, сборки по URL-адресам с протоколами, отличными от file:, сначала загружаются в кэш загрузки перед загрузкой.

В листинге 2.2 показана простая программа на C #, которая загружает сборку, расположенную в file://C:/usr/bin/xyzzy.dll, а затем создает экземпляр содержимого типа с именем AcmeCorp.LOB.Customer. В этом примере все, что предоставляет вызывающая сторона, - это физическое местоположение сборки. Когда программа использует загрузчик сборки таким способом, CLR игнорирует четырехсимвольное имя сборки, включая номер версии.

Пример 2. 2. Загрузка сборки с явным CODEBASE

using System;
using System.Reflection;
public class Utilities {
  public static Object LoadCustomerType() {
    Assembly a = Assembly.LoadFrom(
                    "file: //C:/usr/bin/xyzzy. dll") ;
    return a.CreateInstance("AcmeCorp.LOB.Customer") ;
  }
}

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

Средство распознавания сборки предоставляется разработчикам с помощью метода Load класса System.Reflection.Assembly. Как показано в листинге 2.3, этот метод принимает имя сборки из четырех частей (либо в виде строки, либо в виде ссылки на AssemblyName), и внешне он похож на метод LoadFrom, предоставляемый загрузчиком сборки. Сходство очень глубокое, потому что метод Load сначала использует распознаватель сборки, чтобы найти подходящий файл, используя довольно сложную последовательность операций. Первая из этих операций - применить политику версий, чтобы точно определить, какая версия нужной сборки должна быть загружена.

Пример 2.3. Загрузка сборки с помощью Resolver Assembly

using System;
using System.Reflection;
public class Utilities {
  public static Object LoadCustomerType() {
    Assembly a = Assembly.Load(
      "xyzzy, Version=1. 2. 3.4, " +
      "Culture=neutral, PublicKeyToken=9a33f27632997fcc") ;
    return a.CreateInstance("AcmeCorp.LOB.Customer") ;
  }
}
2 голосов
/ 03 июня 2010

Это немного от вашего вопроса, но вы можете загрузить все сборки одновременно, если вы предпочитаете, чтобы это не происходило по требованию. Нечто подобное должно сработать

foreach (AssemblyName asn in Assembly.GetExecutingAssembly().GetReferencedAssemblies())
{
    var asm = Assembly.Load(fn);
    // I've found get types does a good job of ensuring the types are loaded.
    asm.GetTypes();
}
1 голос
/ 03 июня 2010

CLR загружает сборки по требованию. Когда вы выполняете метод, он смотрит, где он находится (какой модуль и т. Д.), И если он не загружен, он загружает его.

Вот статья о производительности CLR и рассказывается о загрузке сборок:

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

Эта статья предназначена для SilverLight, но она немного говорит о том, что происходит с CLR.

0 голосов
/ 03 июня 2010

COM DLL загружаются по требованию всякий раз, когда создается соответствующий COM-объект. Это также может происходить с не COM-библиотеками.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...