Компиляция кода.NET или усложнение?
Q1) Почему C# изначально компилируется в IL, а затем во время выполнения JIT соблюдается и запускается поверх виртуальной машины (?). Или это JIT соответствует родному машинному коду?
Q2) Если второе верно (JIT соответствует собственному машинному коду), то где находится песочница.NET, в которой выполняется код?
Q3) Кроме того, почему код компилируется в IL в первую очередь. Почему бы просто не скомпилировать в машинный код все время? Существует инструмент от MS, который называется ngen, но почему это необязательно?
6 ответов
IL - это JIT'd (JIT = Just In Time), скомпилированный с собственным машинным кодом при запуске процесса.
Использование уровня виртуальной машины позволяет.NET вести себя согласованно на разных платформах (например, int всегда 32-битный независимо от того, работаете ли вы на 32- или 64-битной машине, это не относится к C++).
JIT-компиляция позволяет оптимизациям динамически приспосабливаться к коду во время его выполнения (например, применять более агрессивную оптимизацию к частям вызываемого кода или использовать аппаратные инструкции, доступные на конкретной машине, такой как SSE2), с которыми вы не можете справиться статический компилятор.
A1) JIT компилируется в машинный код
А2) В.net нет такого термина как песочница. Вместо этого есть AppDomains. И они запускаются как часть CLR (т.е. как часть исполняемого процесса)
A3) Недостатки NGen от Джеффри Рихтера:
NGen'd файлы могут выйти из синхронизации. Когда CLR загружает файл NGen'd, он сравнивает ряд характеристик о ранее скомпилированном коде и текущей среде выполнения. Если какие-либо характеристики не совпадают, файл NGen'd не может быть использован, и вместо него используется обычный процесс JIT-компилятора.
Низкая производительность по времени загрузки (перебазирование / связывание). Файлы сборки - это стандартные файлы Windows PE, и каждый из них содержит предпочтительный базовый адрес. Многие разработчики Windows знакомы с проблемами, связанными с базовыми адресами и перебазированием. Когда JIT компилирует код, эти проблемы не имеют значения, потому что правильные ссылки на адреса памяти вычисляются во время выполнения.
Низкая производительность во время исполнения. При компиляции кода NGen не может сделать столько предположений о среде исполнения, сколько компилятор JIT может. Это приводит к тому, что NGen.exe создает худший код. Например, NGen не оптимизирует использование определенных инструкций процессора; он добавляет косвенные ссылки для доступа к статическим полям, потому что фактический адрес статических полей не известен до времени выполнения. NGen вставляет код для вызова конструкторов классов везде, потому что он не знает порядок, в котором будет выполняться код, и если конструктор класса уже был вызван.
Вы можете использовать NGEN для создания собственных версий ваших сборок.NET. Это означает, что JIT не должен делать это во время выполнения.
.NET сначала компилируется в IL, а затем в нативный, поскольку JIT был разработан для оптимизации кода IL для текущего процессора, под которым выполняется код.
Код.NET компилируется в IL для совместимости. Поскольку вы можете создавать код с использованием C#, VB.NET и т. Д., JIT необходим общий набор команд (IL) для компиляции в собственный код. Если JIT должен был знать о языках, то JIT нужно будет обновлять при выпуске нового языка.NET.
Я не уверен насчет вопроса о песочнице, я думаю, что приложение.NET работает с 3 доменами приложений. Один домен содержит среды выполнения.NET (mscorlib, system.dll и т. Д.), Другой домен содержит ваш код.NET, и я не могу вспомнить, для чего предназначен другой домен. Проверьте http://my.safaribooksonline.com/9780321584090
Скомпилированный код.Net становится IL, который является промежуточным языком точно так же, как и код объекта Javas. Да, можно генерировать машинный код с помощью инструмента NGen. NGen связывает результирующий собственный образ с машиной, поэтому копирование двоичного файла ngen в другую систему не даст ожидаемых результатов. Компиляция в промежуточный код позволяет принимать решения, которые могут быть приняты во время выполнения, которые иначе (легко) не могут быть приняты с помощью языка со статической типизацией, такого как C++, это также позволяет функционировать кодом на различных аппаратных архетектурах, потому что код становится описательным в ощущение, что он также описывает намерение того, что должно происходить в битовом (например, 32 или 64)-агностическом смысле, в отличие от машинно-специфичного кода, который работает только в 32-битных или 64-битных системах, но не в обоих.
Кроме того, NGen является необязательным, потому что, как я уже сказал, он связывает двоичный файл с системой, он может быть полезен, когда вам нужна производительность скомпилированного машинного кода с гибкостью динамически типизированного языка, и вы знаете, что двоичный файл не будет перемещаться в система, с которой он не связан.
1. C# скомпилирован в CIL (или IL), потому что он разделяет платформу с остальными языками.NET (именно поэтому вы можете написать DLL на C# и использовать ее в VB.NET или F# без проблем). Затем CLR JIT скомпилирует код в машинный код.
.NET также может работать на нескольких платформах (Mono на *NIX и OS X). Если C# скомпилирован в нативный код, это будет не так просто.
2. Песочницы нет.
3. Охвачено в ответе на #1
A1) Таким образом, он не зависит от платформы (Windows, Linux, Mac) и может также использовать определенные оптимизации для вашего текущего оборудования. Когда JIT скомпилируется, он превращается в машинный код.
A2) Вся инфраструктура (.NET Framework) - это все песочница, поэтому все вызовы, которые вы можете сделать через свое приложение, будут проходить через песочницу.NET Framework.
A3) Как и в ответе 1, он позволяет двоичному файлу.NET работать на разных платформах и выполнять определенные оптимизации на клиентском компьютере на лету.