2009-03-02 1 views
36

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

+0

Я изложил свой ответ, так как вы его приняли. Если это делает его слишком многословным и не более того, что вы считаете приемлемым ответом, добавьте комментарий, чтобы сказать это, и я скрою его/верну его. Просто было стыдно потерять информацию от других ответов – ShuggyCoUk

ответ

42

JIT-это один аспект CLR.

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

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

Чтобы обратиться к добавлению дженериков.

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

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

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

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

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

64

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

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

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

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

Это то, что это будет выглядеть на C#

C# Код > компилятора C# > IL > .NET время выполнения > JIT компилятор > Machinecode > Execution

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

Код VB > VB компилятор > IL > .NET время выполнения > JIT компилятор > Machinecode > Execution

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

+2

-1 для обращения к IL в качестве байт-кода, это семантика Java. IL (ранее MSIL) - правильный термин, не путайте эти два. Измените это, и вы получили мой голос. –

+0

@John Leidegren: Хороший момент, изменил его. – thr

+0

Верно ли, что JIT компилирует код для машинного кода при первом запуске программы, и после этого компиляция пропущена и скомпилированный код используется? Если это так, возможно, стоит включить это в ваш ответ. –

23

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

+1

@Ted: Вас это интересовало? Я не дал более подробного объяснения (например, Fredrik's), потому что я полагал, что вы уже знали большинство подобных вещей и интересовались отношениями между CLR и JIT. –

+0

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

27

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

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

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

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

Черт побери! Прекратите называть его байт-код, это IL, промежуточное представление языка. Поскольку размер инструкций IL - это 16-разрядные слова. –

+1

Я боюсь, что вы сражаетесь с проигранной битвой на этом Джоне :) Я думаю, что «Промежуточный код» - разумный общий термин, в который вы хотите включить java, «net's», LLVM и т. Д., Но черт возьми, если байт-код не мгновенно ... – ShuggyCoUk

+0

Если вы говорите байт-код, я бы предположил, что вы говорите о байт-коде Java. Если вы скажете IL, я предполагаю, что вы говорите о платформе .NET. Это так просто. Я хочу сохранить это различие живым. –

15

Я знаю, что нить довольно старая, но я думал, что смогу нарисовать картинку, которая заставила меня понять JIT. Это отличная книга CLR via C# by Jeffrey Ritcher. В картине, метаданные, он говорит о том, метаданных, излучаемые в заголовке сборки, где хранится вся информация о типах в сборке:

JIT image from CLR via C#

2

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

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

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

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

+0

Micro ** S ** oft? Зачем? –