2. Исполнительный механизм находит класс, содержащий "главную" точку входа "main", с которой должно начинаться выполнение приложения.
Таковым является класс с сигнатурой функции, соответствующей виду static void Main. В случае обнаружения типа с такой сигнатурой происходит загрузка класса и производится попытка выполнения "главной" процедуры (шаги 3 и 4).3. Загружается класс.
Информация о классе загружается и верифицируется с той целью, чтобы убедиться в корректности и согласованности определения класса. Все методы (то есть точки входа исполняемого кода) класса обозначаются как "некомпилированные".4. Исполнительный механизм пытается выполнить указанную процедуру.
Если уже имеется откомпилированный код, связанный с процедурой, осуществляется выполнение этого кода.5. Если исполнительный механизм обнаруживает, что свойство или метод, которые требуется запустить на выполнение, не откомпилированы, они компилируются по требованию.
Производится загрузка содержащейся в классе информации, которая необходима методу. Код верифицируется для гарантии того, что он содержит безопасные, допустимые и корректно сформированные IL-инструкции, а затем подвергается JIT-компиляции. Если метод ссылается на другие типы, которые еще не были загружены, осуществляется необходимая загрузка определений соответствующих классов и типов. Методы, содержащиеся в классах, не компилируются до тех пор, пока в этом не возникнет необходимости; именно в этом и состоит смысл JIT-компиляции.6. Выполняется скомпилированный к этому моменту метод.
Если возникает необходимость в распределении памяти для типов или методов, исполнительному механизму направляются соответствующие запросы. Любые вызовы классов методами возвращают нас к шагу 5.На первый взгляд, вышеперечисленные действия требуют выполнения большого объема работы, однако в действительности все происходит очень быстро.