Опубликован: 30.01.2013 | Уровень: для всех | Доступ: платный
Лекция 2:

Введение в платформу .NET Framework и ASP.NET

Компиляция приложений .NET

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

  • Исходный код (на языке C#, Visual Basic или др.) преобразуется в MSIL;
  • Код на языке MSIL преобразуется в машинный код.

Теоретически, программный код, разработанный на разных языках программирования в среде .NET (C#, Visual Basic .NET и др.) и преобразованный в код на языке MSIL, в конечном счете, будет иметь одинаковый вид. Кроме того, после преобразования программного кода в MSIL будет затруднительно определить исходный язык программирования.

Для чего необходима подобная двухэтапная компиляция приложения? Те, кто разрабатывал на языках низкого уровня знают, что разработка программного кода имеет специфику при разработке для каждой платформы. Это означает, что разработка приложения для 32- и 64-разрядной платформы может иметь существенные различия. При этом при игнорировании особенностей разработки под конкретную платформу могут быть как некритические последствия (например, в виде снижения производительности), так и критические (например, неработоспособность приложения). В связи с этим зачастую можно видеть два типа пакетов распространения приложения (32- и 64-разрядных). Более того, для более эффективной работы приложения нередко требуется оптимизация его кода. Все эти задачи имеют непростую природу и могут отнимать у разработчика приложения много времени. Разработчик в этом случае должен тратить свое время не на улучшение логики программы, а заботиться об инфраструктурных задачах. Однако, несмотря на всю сложность этого процесса, существуют алгоритмы, которые способны выполнить большую часть работы по оптимизации кода под конкретную платформу без участия человека. Именно этой идеологии придерживается платформа .NET Framework.

При запуске кода на языке IL происходит его преобразование в машинный код. При этом весь процесс преобразования происходит в той среде, где приложение должно быть запущено (на компьютере конечного пользователя, где исполняется приложение). Этот факт позволяет оптимизировать конечный машинный код, который получается в процессе преобразования, для той платформы, в рамках которой он будет исполняться. Также при таком подходе нет необходимости иметь две различных сборки для разных сред (32- и 64-разрядных) – конечный машинный код будет получен с учетом специфики платформы. Поскольку преобразование "MSIL – машинный код" требует определенного времени, среда исполнения записывает полученный машинный код в системных папках и при последующем запуске приложения, которое запускалось ранее, используется уже готовый код. Общий процесс компиляции выглядит следующим образом.


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

Поскольку процесс получения машинного кода является трудоемкой задачей, компилятор JIT работает "по запросу". Дело в том, что JIT-компилятор не пытается получить машинный код для всей сборки в момент запуска приложения – машинный код получается только для той части сборки, которая должна быть исполнена в данный момент. Получение машинного кода для остальных частей сборки происходит в момент запуска этих частей на исполнение.

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

В случае, когда необходимо выполнить предкомпиляцию приложения до его запуска (для предотвращения ситуации компиляции приложения "на лету"), можно воспользоваться утилитой NGen (native image generator), которая поставляется в составе .NET Framework. Утилита NGen использует аналогичные методы компиляции приложения, что и компилятор JIT. Однако, от компилятора JIT эту утилиту отличает три аспекта:

  • преобразование кода MSIL в машинный код производится перед выполнением приложения, а не в момент исполнения;
  • преобразовываются сразу вся сборка, а не отдельные методы;
  • полученный машинный код сохраняется в кэше образа машинного кода в виде файла на жестком диске.

Утилита NGen является консольным приложением и запускается из командной строки. Она позволяет сделать несколько различных действий:

  • скомпилировать сборку и установить ее в кэш сборок (ключ install);
  • удалить сборку из кэша сборок (ключ uninstall);
  • обновить сборку в кэше сборок (ключ update);
  • отобразить состояние процесса компиляции (ключ display);
  • управлять очередью выполнения компиляции (ключ queue).

Общий процесс компиляции приложений .NET представлен на следующей схеме.


Как видно, процесс компиляции приложений .NET – сложный и многогранный процесс. Однако, этот процесс придает гибкость и универсальность приложениям .NET, а встроенные механизмы оптимизации кода позволяют получить более эффективный исполняемый код.

Краткие итоги

Все приложения .NET поставляются в виде скомпилированного кода MSIL. Весь процесс компиляции приложения .NET состоит из двух этапов – преобразования исходного кода программы в код на языке MSIL и преобразование кода MSIL в машинный код. Такой процесс позволяет абстрагироваться от платформы исполнения, а также оптимизировать машинный код под конкретную платформу. Преобразование кода MSIL в машинный код происходит в момент запуска программы JIT-компилятором, а результат сохраняется в специальном кэше. Поэтому первый запуск .NET приложения может осуществляться с небольшой задержкой. Однако, этого можно избежать, если использовать утилиту NGen.

Марина Воробьева
Марина Воробьева
Виктория Ткаченко
Виктория Ткаченко

Проигрыватель не работает. После нажатия кнопки Play ничего не происходит.

Азиз Рахимов
Азиз Рахимов
Россия, М/О Ленинская район г.Видное ул.Центральная д.32
Борис Логунов
Борис Логунов
Россия, Moscow