2010-10-01 2 views
20

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

+0

В большинстве ответов вы не внимательно изучили свой вопрос. Он спрашивает: почему конечная машина не может сделать компиляцию один раз и сохранить ее (не: почему мы не можем компилировать один раз и распространять двоичный файл). – egrunin

+1

Это уже работает именно так. Просмотрите службы, установленные на вашем компьютере. Служба «Microsoft .NET Framework NGEN» активируется для предварительной сборки сборок. Если вы правильно заметили установщик. –

+1

Он не компилируется при каждом запуске. Когда метод JIT компилируется, сгенерированный собственный код сохраняется в кэш-памяти. При последующих запусках, если среда выполнения увидит, что метод уже скомпилирован, он не компилирует его снова. – mhenry1384

ответ

22

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

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

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

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

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

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

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

+1

# 1, вероятно, самая важная причина. – STW

+4

Ни один из этих вопросов не имеет отношения к вопросу: atli спросил о компиляции на целевой машине, а не в машине разработчика. – JasonFruit

+1

@ Джейсон: Ах, ты прав. Я неправильно понял эту часть. Редактирование ... –

5

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

6

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

+1

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

+0

@Michael Это неверно. NGen кэширует скомпилированный код JIT для последующего повторного использования. –

0

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

 
Code --> Machine Code 

Однако в .NET, Java и т.д.то, что вы нацеливаете, является виртуальной машиной . Это создает код, который может интерпретировать любая совместимая с .NET VM, и, в свою очередь, 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) 

Versus

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

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

3

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

+0

Но среда CLR может легко включать номер версии в гипотетическую версию сборки JIT-версии в виде диска и удалять ее при первом запуске в обновленной среде CLR. – binki

2

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

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

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

Тот факт, что 'Expression .Compile()' существует (и что-то еще неопределенно похожее на eval-like), на самом деле, вероятно, является одной из самых больших причин иметь очень хороший JIT. – binki

 Смежные вопросы

  • Нет связанных вопросов^_^