CLR против JIT - PullRequest
       31

CLR против JIT

41 голосов
/ 02 марта 2009

В чем разница между JIT-компилятором и CLR? Если вы компилируете свой код в il, и CLR запускает этот код, то что делает JIT? Как изменилась компиляция JIT с добавлением обобщения в CLR?

Ответы [ 7 ]

73 голосов
/ 02 марта 2009

Вы компилируете свой код в IL, который выполняется и компилируется в машинный код во время выполнения, это то, что называется JIT.

Редактировать , чтобы конкретизировать ответ (еще более упрощенно):

Когда вы компилируете свой код C # в Visual Studio, он превращается в IL, который понимает CLR, IL одинаков для всех языков, работающих поверх CLR (что позволяет среде .NET использовать несколько языков и взаимодействие между ними легко).

Во время выполнения IL интерпретируется в машинный код (который зависит от используемой вами архитектуры) и затем выполняется. Этот процесс называется компиляцией Just In Time или JIT для краткости. Только необходимый IL преобразуется в машинный код (и только один раз он «кэшируется» после компиляции в машинный код), * ​​1009 * как раз во время до его выполнения, отсюда и название JIT.

Вот как это будет выглядеть для C #

Код C # > Компилятор C # > IL > .NET Runtime * > JIT-компилятор > Машинный код > Выполнение

А вот как это будет выглядеть для VB

VB код > VB компилятор > IL > .NET Runtime > JIT компилятор > машинный код > выполнение

И, как вы можете видеть, только два первых шага уникальны для каждого языка, и все после того, как он был превращен в IL, является одним и тем же, что, как я уже говорил, является причиной того, что вы можете использовать несколько разных языков поверх. NET

46 голосов
/ 02 марта 2009

JIT является одним из аспектов CLR.

В частности, именно эта часть отвечает за преобразование CIL / MSIL (в дальнейшем называемого IL), созданного компилятором исходного языка (например, csc.exe для Microsoft c #), в машинный код, родной для текущего процессора (и архитектуры, которую он предоставляет в текущий процесс, например 32 / 64bit). Если рассматриваемая сборка была ngen'd, тогда процесс JIT совершенно не нужен, и CLR без проблем выполнит этот код.

Перед использованием метода, который еще не был преобразован из промежуточного представления, JIT несет ответственность за его преобразование.
Точно когда сработает JIT, зависит от конкретной реализации и может быть изменено. Однако проект CLR требует, чтобы JIT происходил за до , когда соответствующий код выполняется, а JVM, напротив, может свободно интерпретировать код некоторое время, пока отдельный поток создает представление машинного кода.
«Обычный» CLR использует подход pre-JIT-заглушки , где методы JIT компилируются только по мере их использования. Это подразумевает, что исходная заглушка нативного метода является косвенным указанием JIT скомпилировать метод, а затем изменить исходный вызов, чтобы пропустить начальную заглушку. Вместо этого текущая компактная версия компилирует все методы для типа при его загрузке.

Для решения вопроса добавления Generics.

Это было последнее значительное изменение спецификации IL и JIT с точки зрения его семантики, а не внутренних деталей реализации.

Было добавлено несколько новых инструкций IL, и было предоставлено больше опций метаданных для типов инструментов и элементов. Ограничения были добавлены и на уровне IL.

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

Каждый тип значения получит определенный код, сгенерированный для него, и главной причиной этого является уменьшение / увеличение размера переменных в стеке / куче. Кроме того, путем выдачи ограниченного кода операции перед вызовом метода многим вызовам не ссылочных типов не нужно указывать значение для вызова метода (эта оптимизация также используется в неуниверсальных случаях). Это также позволяет правильно обрабатывать поведение по умолчанию <T> и исключать операции сравнения со значением NULL в виде отсутствия операций (всегда false), когда используется тип значения, отличный от Nullable.

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

29 голосов
/ 02 марта 2009

Как говорит Джон Скит, JIT является частью CLR. В основном это то, что происходит под капотом:

  1. Ваш исходный код скомпилирован в байт-код, известный как общий промежуточный язык (CIL).
  2. Метаданные из каждого класса и всех методов (и любой другой вещи: O) включены в PE-заголовок результирующего исполняемого файла (будь то dll или exe).
  3. Если вы создаете исполняемый файл, в PE Header также входит обычный загрузчик, который отвечает за загрузку CLR (общеязыковой среды выполнения) при выполнении исполняемого файла.

Теперь, когда вы выполните:

  1. Загрузчик инициализирует CLR (в основном, загружая сборку mscorlib) и инструктирует его выполнить вашу сборку.
  2. CLR выполняет вашу основную запись.
  3. Теперь у классов есть векторная таблица, в которой хранятся адреса функций метода, поэтому при вызове MyMethod эта таблица ищется, а затем делается соответствующий вызов этого адреса. После запуска ВСЕ записи для всех таблиц имеют адрес JIT-компилятора.
  4. Когда выполняется вызов одного из таких методов, JIT вызывается вместо фактического метода и получает управление. Затем JIT компилирует код CIL в реальный код сборки для соответствующей архитектуры.
  5. Как только код скомпилирован, JIT переходит в таблицу векторов методов и заменяет адрес на один из скомпилированного кода, чтобы каждый последующий вызов больше не вызывал JIT.
  6. Наконец, JIT обрабатывает выполнение скомпилированного кода.
  7. Если вы вызываете другой метод, который еще не был скомпилирован, вернитесь к 4 ... и так далее ...
26 голосов
/ 02 марта 2009

JIT - это в основном часть CLR. Сборщик мусора - это другое. Вопрос о том, куда вы возлагаете ответственность за взаимодействие и т. Д., - это другой вопрос, в котором я крайне недооценен для комментариев :)

15 голосов
/ 24 февраля 2011

Я знаю, что ветка довольно старая, но я подумал, что мог бы вставить картинку, которая заставила меня понять JIT. Это из отличной книги Джеффри Ритчера CLR via C # . На рисунке метаданные, о которых он говорит, - это метаданные, генерируемые в заголовке сборки, где хранится вся информация о типах в сборке:

JIT image from CLR via C#

2 голосов
/ 09 марта 2012

1) при компиляции программы .net программный код .net преобразуется в код промежуточного языка (IL)

2) после выполнения программы код промежуточного языка преобразуется в собственный код операционной системы, как и когда вызывается метод; это называется JIT (Just in Time) компиляцией.

0 голосов
/ 05 мая 2014
  1. Common Language Runtime (CLR) - интерпретатор, а Just In Time (JIT) - компилятор в .Net Framework.

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

...