Компиляция C# JIT and.NET


Я немного запутался в деталях того, как работает JIT-компилятор. Я знаю, что C# компилируется до IL. При первом запуске он JIT'D. включает ли это его перевод в собственный код? Является ли среда выполнения .NET (как виртуальная машина?) взаимодействие с JIT-компилятором кода? Я знаю, что это наивно, но я действительно запутался. У меня всегда было впечатление, что сборки не интерпретируются средой выполнения .NET, но я не понимаю деталей взаимодействия.

4 66

4 ответа:

Да, код JIT'ING IL включает в себя перевод IL в собственные машинные инструкции.

да, среда выполнения .NET взаимодействует с собственным машинным кодом JIT'ed, в том смысле, что среда выполнения владеет блоками памяти, занятыми собственным машинным кодом, среда выполнения вызывает собственный машинный код и т. д.

вы правы, что среда выполнения .NET не интерпретирует код IL в ваших сборках.

Что происходит, когда выполнение достигает функция или блок кода (например, предложение else блока if), который еще не был скомпилирован JIT в собственный машинный код, jit'R вызывается для компиляции этого блока IL в собственный машинный код. Когда это сделано, выполнение программы вводит свежеиспеченный машинный код для выполнения его логики программы. Если во время выполнения этого собственного машинного кода выполнение достигает вызова функции функции, которая еще не была скомпилирована в машинный код, jit'R вызывается для компиляции это "точно в срок." И так далее.

JIT'R не обязательно компилирует всю логику тела функции в машинный код сразу. Если функция имеет операторы if, блоки операторов предложений if или else не могут быть скомпилированы JIT до тех пор, пока выполнение фактически не пройдет через этот блок. Пути кода, которые не были выполнены, остаются в форме IL, пока они не будут выполнены.

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

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

код "компилируется"на промежуточный язык Microsoft, который аналогичен формату сборки.

когда вы дважды щелкните исполняемый файл, Windows загружает mscoree.dll который затем настраивает среду CLR и запускает код вашей программы. JIT-компилятор начинает чтение кода MSIL в вашей программе и динамически компилирует код в инструкции x86, которые может выполнять процессор.

.NET использует промежуточный язык MSIL, иногда сокращенно IL. Компилятор считывает исходный код и создает MSIL. При запуске программы компилятор .NET Just In Time (JIT) считывает код MSIL и создает исполняемое приложение в памяти. Вы не увидите ничего из этого, но это хорошая идея, чтобы знать, что происходит за кулисами.

я опишу компиляцию кода IL в собственные инструкции CPU с помощью примера ниже.

public class Example 
{
    static void Main() 
    {
        Console.WriteLine("Hey IL!!!");
    }
}

в первую очередь CLR знает все подробности о типе и какой метод вызывается из этого типа это связано с метаданными .

когда CLR начинает выполнять IL в собственной инструкции CPU, что время CLR выделяют внутренние структуры данных для каждого типа, на который ссылается код Main.

в нашем случае у нас есть только один тип консоли, поэтому CLR выделит один внутренняя структура данных через эту внутреннюю структуру мы получим доступ к ссылочным типам

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

при инициализации этой структуры среда CLR устанавливает каждую запись в undocumented функции содержится внутри в самой CLR.И как вы можете догадаться это функцииэто то, что мы вызовите JIT-компилятор.

в целом вы можете рассматривать JIT-компилятор как функцию CLR, которая компилирует IL в собственные инструкции CPU. Позвольте мне показать вам, как этот процесс будет в нашем примере.

1.Когда Main делает свой первый вызов WriteLine, вызывается функция JITCompiler.

2.Функция компилятора JIT знает, какой метод вызывается и какой тип определяет этот метод.

3.Затем JIT-компилятор ищет сборку, где определите этот тип и получите код IL для метода, определенного этим типом в нашем случае код IL метода WriteLine.

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

5.Затем JIT-компилятор возвращается к записи внутренней структуры данных и заменяет адрес (который в первую очередь ссылается на реализацию кода IL WriteLine) с помощью адрес новый динамически созданный блок памяти, который содержит собственные инструкции процессора WriteLine.

6.Наконец, функция JIT-компилятора переходит к коду в блоке памяти. Этот код является реализацией метода WriteLine.

7.После реализации WriteLine код возвращается к основному коду, который продолжает выполнение в обычном режиме.