Почему .net использует JIT-компилятор вместо простой компиляции кода на целевой машине? - PullRequest
21 голосов
/ 02 октября 2010

Название в значительной степени подводит итог, но мне было интересно, почему такие системы, как .net, компилируют код каждый раз, когда он запускается, а не просто компилируют его один раз на целевой машине?

Ответы [ 6 ]

25 голосов
/ 02 октября 2010

При использовании промежуточного формата, такого как .NET или Java, можно получить две вещи:

  1. Вы можете запустить программу на любой платформе именно потому, что код представлен в промежуточном формате.родного кода.Вам просто нужно написать интерпретатор для промежуточного формата.
  2. Он допускает некоторые оптимизации во время выполнения, которые (легко) невозможны во время компиляции: например, вы можете воспользоваться специальными функциями в новомПроцессоры, даже если эти процессоры не существовали, когда вы писали свою программу - об этом должен знать только JIT-компилятор.

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

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

Если вы начинаете кэшировать JIT-кодированный код между сеансами, вам нужно отслеживать, что уже скомпилировано, и затем сохранять его на диске.Для большой программы у вас может быть много встроенного кода для загрузки с диска.Дисковый ввод-вывод довольно дорогой, поэтому ожидание диска может занять больше времени, чем повторная его JIT.Кроме того, вам нужно следить за тем, как долго этот кэш может использоваться.Если аппаратное обеспечение меняется, вы можете повторно выполнить JIT, чтобы применить некоторые новые оптимизации.Если программа изменится, вы не сможете использовать ваш старый скомпилированный код.Если во время выполнения компилятор изменится, возможно, исправлена ​​ошибка безопасности, и вам нужно перекомпилировать, чтобы убедиться, что ошибка не сохраняется в вашем собственном коде.

По сути, JIT-компилятор неожиданно имеетгораздо больше работы (включая дисковый ввод / вывод для работы с кешем), и она становится намного более сложной и медленной, уменьшая суть JIT'ing.

Теперь это не означает, что он может 'Иногда бывает полезно предварительно скомпилировать определенные сборки, и, как указывает Мэтью Феррейра, это то, что может сделать инструмент ngen, но в общем случае это просто не стоит делать, потому что JIT-компиляция часто бывает более чем достаточно быстрой.

6 голосов
/ 02 октября 2010

Я не пишу компиляторы или среды выполнения, поэтому я не могу сказать это наверняка, но я не верю точно в срок = каждый раз.Это просто означает, что мы ждем, пока нам действительно не понадобится компилировать, но как только компиляция будет выполнена для этого экземпляра, она больше не будет компилироваться.

5 голосов
/ 02 октября 2010

Что если вы перенесли исполняемый файл на другую машину?Если он был скомпилирован один раз для конкретного процессора первой машины, он не сможет воспользоваться (возможно) более продвинутым или эффективным набором инструкций, доступным на новом процессоре.Если вы действительно хотите скомпилировать один раз на целевом компьютере, попробуйте использовать ngen.exe во время установки приложения.

3 голосов
/ 02 октября 2010

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

2 голосов
/ 08 марта 2012

Название в значительной степени подводит итог, но мне было интересно, почему такие системы, как .net, компилируют код каждый раз, когда он запускается, а не просто компилируют его один раз на целевой машине?

.NET кеширует результаты компиляции CIL в собственный код для заданной цели, но это не тривиально:

  • Существует компромисс между загрузкой кэшированных данных с диска и перекомпиляцией на лету.
  • Любая форма генерации кода во время выполнения требует умения компилировать на лету.Это не только использование System.Reflection.Emit, но также повторное использование типов из динамически загружаемых сборок и даже создание новых типов значений во время полиморфной рекурсии.
0 голосов
/ 02 октября 2010

Если вы компилируете непосредственно в машинный код, то вы нацелены на конкретную систему:

Code --> Machine Code

Однако в .NET, Java и т. Д. Вы нацеливаетесь на виртуальную машину .Это создает код, который может интерпретировать любая .NET-совместимая ВМ, и, в свою очередь, превращает JIT в реальный машинный код.

Итак, в .NET:

Code --> IL --> VM (executing) --> JIT'd Machine Code

Изначально это выглядит сложнее, но рассмотримнацеливание на несколько архитектур:

Code(x86) --> Machine Code(x86)
Code(ppc) --> Machine Code(ppc)
etc... (1x code-set per target)

по сравнению с

Code --> IL --> VM(x86) (executing) --> JIT'd x86 Machine Code
                VM(ppc) (executing) --> JIT'd ppc Machine Code
                etc...

Моя иллюстрация грубая, но вы заметите, что один пакет кода .NET может предназначаться и работать на нескольких платформах

...