JIТ-компилятор и CLR

Код С# компилируется в код на языке IL, a IL — это то, что обрабатывает CLR. Спецификация IL включена в стандарт CLI. Чтобы посмотреть, как выглядит код IL, можно загрузить приложение “Hello World!” в программу дизассемблера Intermediate Language Disassembler (ILDASM), входящую в состав .NET SDK1. ILDASM покажет древовидное представление типов данных из сборки.

Кроме того, можно открывать индивидуальные методы и просматривать код IL, который для них сгенерировал компилятор С#. Как видно в коде, IL выглядит подобно языку ассемблера; по сути, это и есть язык ассемблера CLR. Он называется IL, потому что является промежуточным шагом между определенным языком и определенной платформой.

Метод Main в HelloWorld.ехе на языке IL

1
2
3
4
5
6
7
8
9
10
11
.method private hidebysig static void Main() cil managed
{
.entrypoint
// Code size 13 (0xd)
.maxstack 8
IL_0000: nop
IL_0001: ldstr "Hello World!"
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: nop
IL_000c: ret
} // end of method EntryPoint::Main

Среда CLR — это не интерпретатор. Она не производит повторную трансляцию кода IL при каждом его выполнении. Хотя на основе интерпретаторов существует немало гибких решений (таких, например, как интерпретатор JScript для сервера сценариев Windows (Windows Scripting Host)), обычно они не являются эффективными исполняющими платформами.

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

Хотя фаза JIT-компиляции добавляет сложности и изначально отражается на производительности, все же преимущества компилятора JIT в паре с CLR могут перевесить затраты времени на JIT-комггиляцию и в действительности создать более эффективный код, чем у “родных” скомпилированных приложений. Ниже описаны причины.

• Управляемые приложения могут потреблять меньше памяти, В общем случае IL-код занимает меньше места в памяти, чем “родной” машинный код. Другими словами, рабочий набор управляемых приложений, т.е. количество страниц памяти, потребляемых приложением, обычно меньше, чем у “родных” приложений.

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

• JIT-компиляции подвергается только тот код, который выполняется. IL-код обычно более компактен, чем машинный код, поэтому сокращение компилируемого кода до минимума уменьшает образ памяти приложения.

• В результате JIТ-компиляции получается высоко оптимизированный код. При компиляции типичных “родных” приложений код оптимизируется на основе обобщений, таких как типичная топология компьютерной системы. Код после JIT-компиляции оптимизирован непосредственно для платформы, на которой он выполняется в данный момент. JIT-компилятор может учитывать весьма специфичные параметры платформы во время оптимизации скомпилированного кода и часто генерирует намного более производительный код, чем у статически скомпилированных “родных” приложений.

• Среда CLR может отслеживать частоту вызовов. Если CLR видит, что раздел JIT-компилированного кода не вызывался в течение длительного времени, то может освободить место, занятое им. При следующем вызове код будет перекомпилирован снова.

CLR также может проводить оптимизацию во время выполнения. В “родных” приложениях оптимизация задается во время компиляции. Но поскольку в среде CLR оптимизация происходит во время выполнения, она может быть применена в любой момент. Иногда случается так, что реализация CLR сможет компилировать код быстрее, но с меньшей степенью оптимизации, и она может так поступать по умолчанию.

Однако для кода, который вызывается часто, может быть выполнена перекомпиляция с включенной оптимизацией, чтобы он выполнялся быстрее. Например, модель эффективности CLR значительно изменяется в зависимости от того, сколько центральных процессоров установлено на целевой платформе, или даже в зависимости от того, к какому семейству принадлежит центральный процессор. Чтобы приспособиться к такой ситуации, для “родных” приложений приходится выполнять много ручной работы — будь то во время выполнения или во время компиляции.

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

Вдобавок CLR может выполнять оптимизацию ветвей в любой момент, перекомпилируя их JIТ-компилятором, в то время как в “родных” приложениях приходится применять так называемую управляемую профилем оптимизацию (Profile-Guided Optimization) — оптимизацию на основе предположений разработчика относительно наиболее вероятной конфигурации платформы, на которой пользователь будет запускать приложение.

Другими словами, в случае “родного” приложения оптимизация строится на базе предположений, тогда как в случае CLR — на реальных данных о платформе, на которой выполняется приложение.

Это лишь некоторые аргументы, доказывающие, что CLR является гибкой целевой платформой, и почему ее преимущества перевешивают ущерб для производительности, вызванный начальной JIТ-компиляцией.

Вы можете следить за любыми ответами на эту запись через RSS 2.0 ленту. Вы можете оставить ответ, или trackback с вашего собственного сайта.

Оставьте отзыв

XHTML: Вы можете использовать следующие теги: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

 
Rambler's Top100