Почему интерпретаторы компилируют код каждый раз при запуске программы? - PullRequest
0 голосов
/ 16 марта 2019

Мой вопрос касается всех интерпретируемых языков, но чтобы лучше проиллюстрировать свою точку зрения, я буду использовать Java в качестве примера.

Что я знаю для Java, так это то, что когда программисты пишут свой код, они должны компилировать его в байтовые коды Java, которые похожи на машинный язык для универсальной архитектуры виртуальных машин Java.Затем они могут распространять свой код на любую машину, на которой работает виртуальная машина Java (JVM).Тогда JVM - это просто программа, которая берет байт-коды java и компилирует их (для конкретной архитектуры) каждый раз, когда я запускаю свою программу.Из моего понимания (пожалуйста, исправьте меня, если я ошибаюсь здесь), если я запускаю свой код, JVM скомпилирует его на лету, моя машина выполнит скомпилированные инструкции, и когда я закрою программу, вся работа по компиляции будет потеряна, толькочтобы быть сделано снова, во второй раз я хочу запустить свою программу.Это также причина, почему обычно интерпретируемые языки работают медленно, потому что они должны компилироваться каждый раз на лету.

Однако все это не имеет смысла для меня.Почему бы не загрузить байт-коды java на мой компьютер, заставить JVM скомпилировать их для моей конкретной архитектуры один раз и создать исполняемый файл, а затем в следующий раз, когда я захочу запустить программу, я просто запускаю скомпилированный исполняемый файл.Таким образом, обещание Java: «пиши один раз, беги везде» все еще сохраняется, но без большей части медлительности интерпретируемых языков.

Я знаю, что во время компиляции JVM выполняет некоторые умные динамические оптимизации;однако их цель - не только компенсировать медлительность механизма интерпретации?Я имею в виду, что если JVM придется компилировать один раз, запускать несколько раз, то не перевесит ли это ускорение оптимизаций, выполняемых JVM?,У кого-нибудь есть объяснение?

Ответы [ 2 ]

1 голос
/ 16 марта 2019

Это неверно:

В этом случае JVM - это просто программа, которая берет байт-коды Java и компилирует их (для конкретной архитектуры) каждый раз, когда я запускаю свою программу.

JVM содержит интерпретатор байт-кода и , а также оптимизирующий компилятор байт-кода. Он интерпретирует байт-код вашей программы и компилирует байт-код в собственный код, если это необходимо по соображениям производительности, чтобы оптимизировать «горячие точки» в коде.

Чтобы ответить на ваш вопрос, почему бы не сохранить этот скомпилированный результат, есть несколько вопросов:

  • Ему понадобится место для его хранения.
  • Это должно было бы обработать соединение в скомпилированных частях с частями, которые не стоили компилировать (или компилировать все это).
  • Требуется надежный способ узнать, был ли обновлен кэшированный скомпилированный код.
  • Оптимизированный скомпилированный код для программы, запускаемой с аргументами A, B и C, может быть неоптимальным, если программа запускается с аргументами X, Y и Z. Поэтому ему придется обрабатывать эту возможность, либо угадывание исходной компиляции или запоминание аргументов (что было бы несовершенно: например, если они были именами файлов или URL-адресами, их содержимое не сохранялось) и т. д.
  • Во многом это не нужно, компиляция не занимает много времени. Компиляция байт-кода в машинный код занимает не так много времени, как компиляция исходного кода в машинный код.

Поэтому я думаю, что ответ таков: он сложен и подвержен ошибкам, поэтому цена не стоит выгоды.

0 голосов
/ 16 марта 2019

Любое такое утверждение о том, что делают «переводчики», подлежит наблюдению, что не все переводчики одинаковы.

Например, интерпретатор Python берет исходные файлы .py и запускает их. По дороге он генерирует «скомпилированные» файлы .pyc. В следующий раз, когда вы запустите те же файлы .py, этап «компиляции» можно пропустить, если файлы .py не были изменены. (Я говорю «компиляция» в кавычках, поскольку AFAIK результат не машинный код).

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

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

Что касается компромисса / интерпретации: один из факторов - это как долго выполняется ваша программа и как долго она будет меняться. Если вы используете короткие «студенческие» программы, которые, скорее всего, выполняются только один раз перед изменением, нет смысла вкладывать много усилий в компиляцию. С другой стороны, если ваша программа управляет устройством, которое, вероятно, будет включено в течение нескольких недель, компиляция JIT в устройстве стоит того, и повторять ее после перезагрузки устройства не составляет особого труда.

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

...