C# JIT компиляция и.NET
Я немного запутался в деталях работы компилятора JIT. Я знаю, что C# компилируется в IL. Первый раз, когда он запускается, это JIT'd. Это связано с переводом на нативный код? Взаимодействует ли среда выполнения.NET (как виртуальная машина?) С кодом JIT? Я знаю, что это наивно, но я действительно запутался. У меня всегда складывалось впечатление, что сборки не интерпретируются средой выполнения.NET, но я не понимаю деталей взаимодействия.
4 ответа
Да, JIT-код IL включает перевод IL в машинные инструкции.
Да, среда выполнения.NET взаимодействует с собственным машинным кодом JIT в том смысле, что среда выполнения владеет блоками памяти, занятыми собственным машинным кодом, вызовы среды выполнения в собственном машинном коде и т. Д.
Вы правы в том, что среда выполнения.NET не интерпретирует код IL в ваших сборках.
Что происходит, когда выполнение достигает функционального или кодового блока (например, предложения else блока if), который еще не был скомпилирован JIT в машинный код, JIT'r вызывается для компиляции этого блока IL в машинный код, Когда это сделано, выполнение программы вводит только что выданный машинный код, чтобы выполнить его программную логику. Если во время выполнения этого собственного машинного кода происходит выполнение вызова функции, которая еще не была скомпилирована в машинный код, JIT'r вызывается для компиляции этой функции "вовремя". И так далее.
JIT'r не обязательно компилирует всю логику тела функции в машинный код сразу. Если функция имеет операторы if, блоки операторов предложений if или else не могут быть скомпилированы JIT до тех пор, пока выполнение фактически не пройдет через этот блок. Пути кода, которые не были выполнены, остаются в форме IL до тех пор, пока они не будут выполнены.
Скомпилированный машинный код сохраняется в памяти, чтобы его можно было использовать снова при следующем выполнении этого раздела кода. При втором вызове функции она будет работать быстрее, чем при первом вызове, поскольку во второй раз шаг JIT не требуется.
В настольном.NET собственный машинный код хранится в памяти на протяжении всего жизненного цикла домена приложения. В.NET CF собственный машинный код может быть отброшен, если приложению не хватает памяти. Это будет JIT, скомпилированный снова из исходного кода IL при следующем прохождении кода.
Код "компилируется" в промежуточный язык Microsoft, который похож на формат сборки.
При двойном щелчке исполняемого файла Windows загружается mscoree.dll
который затем устанавливает среду CLR и запускает код вашей программы. JIT-компилятор начинает читать код MSIL в вашей программе и динамически компилирует код в инструкции x86, которые может выполнять ЦП.
Ниже я опишу компиляцию кода IL в нативные инструкции процессора.
public class Example
{
static void Main()
{
Console.WriteLine("Hey IL!!!");
}
}
Прежде всего, CLR знает все детали о типе и о том, какой метод вызывается из этого типа, это связано с метаданными.
Когда CLR начинает выполнять IL в собственной инструкции CPU, CLR выделяет внутренние структуры данных для каждого типа, на который ссылается код Main.
В нашем случае у нас только один тип консоли, поэтому CLR будет выделять одну внутреннюю структуру данных через эту внутреннюю структуру, мы будем управлять доступом к ссылочным типам.
внутри этой структуры данных CLR содержит записи обо всех методах, определенных этим типом. Каждая запись содержит адрес, по которому можно найти реализацию метода.
При инициализации этой структуры CLR устанавливает каждую запись в недокументированном FUNCTION, содержащемся внутри самого CLR. И, как вы можете догадаться, этот FUNCTION - это то, что мы называем JIT Compiler.
В целом, вы можете рассматривать JIT Compiler как функцию CLR, которая компилирует IL в нативные инструкции процессора. Позвольте мне показать вам подробно, как этот процесс будет в нашем примере.
1. Когда Мэйн делает свой первый вызов WriteLine, вызывается функция JITCompiler.
2. Функция JIT Compiler знает, какой метод вызывается и какой тип определяет этот метод.
3. Затем Jit Compiler ищет сборку, в которой определен этот тип, и получает IL-код для метода, определенного этим типом, в нашем случае IL-код метода WriteLine.
4. JIT-компилятор выделяет блок памяти DYNAMIC, после чего JIT проверяет и компилирует код IL в собственный код CPU и сохраняет этот код CPU в этом блоке памяти.
5. Затем JIT-компилятор возвращается к внутренней записи структуры данных и заменяет адрес (который в первую очередь ссылается на реализацию кода ILLine в коде IL) на адрес нового динамически создаваемого блока памяти, который содержит собственные инструкции CPU для WriteLine.
6. Наконец, функция JIT Compiler переходит к коду в блоке памяти. Этот код является реализацией метода WriteLine.
7.После реализации WriteLine код возвращается в код Mains, который продолжает выполнение в обычном режиме.
.NET использует промежуточный язык MSIL, иногда сокращенно обозначаемый как IL. Компилятор читает ваш исходный код и выдает MSIL. Когда вы запускаете программу, компилятор.NET Just In Time (JIT) считывает ваш код MSIL и создает исполняемое приложение в памяти. Вы не увидите ничего подобного, но это хорошая идея, чтобы знать, что происходит за кулисами.
.NET Framework использует среду CLR для создания MSIL(Microsoft Intermediate Language), также называемого IL. Компилятор читает ваш исходный код, и когда вы собираете / компилируете свой проект, он генерирует MSIL. Теперь, когда вы наконец запустите свой проект, в действие вступит.NET JIT ( Just-in-time Compiler). JIT читает ваш код MSIL и создает собственный код (который является инструкциями x86), который может быть легко выполнен CPU.JIT читает все инструкции MSIL и выполняет их построчно.
Если вам интересно посмотреть, что происходит за кулисами, на это уже есть ответ. Пожалуйста, следуйте - Здесь