Почему JVM не компилирует всю программу заранее, вместо того, чтобы компилировать ее по частям? - PullRequest
12 голосов
/ 26 апреля 2011

Для этой темы Герберт Шильдт пишет:

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

Какие проверки во время выполнения он имеет в виду?

Пожалуйста, объясните причину компиляции байт-кода, а не всю программу.

Ответы [ 5 ]

3 голосов
/ 26 апреля 2011

Может быть несколько причин, чтобы скомпилировать его по частям (это первые две, которые приходят мне в голову):

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

И я не знаю, является ли этот сайт точным, но я многому научился у него: http://www.artima.com/insidejvm/ed2/index.html

2 голосов
/ 26 апреля 2011

Одна из возможных причин: среда выполнения Java является очень динамичной средой.Классы загружаются и выгружаются все время.В зависимости от используемых в настоящее время классов возможна или невозможна определенная оптимизация.Например, если у вас есть интерфейс A и единая реализация ImplA, все вызовы методов в интерфейсе A могут быть изменены для использования прямых вызовов методов ImplA без каких-либо действий с виртуальными методами.После загрузки другого класса AnotherImplA такая оптимизация больше не возможна.После того, как AnotherImplA выгружен, это снова возможно.

В JVM существует множество оптимизаций, в которых используются данные, собранные во время выполнения.Выполнение всех оптимизаций заранее упустит множество возможностей.

Проверьте также недавний разговор Клифф Клик, JVM Это делает?

2 голосов
/ 26 апреля 2011

Это рассуждение неверно.Можно скомпилировать всю программу Java сразу в исполняемый код, и фактически gcj делает именно это.

Фактические причины, по которым среды выполнения Java обычно не выполняют предварительную компиляцию:

  • Как часть философии Java «напиши один раз, беги куда угодно», скомпилированный код распространяется как независимый от платформы байт-код, а не как специфичный для платформы собственный код.

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

  • Java API имеют историю, основанную на способности загружать байт-код во время выполнения.(Подумайте обо всем, что зависит от Class.forName и / или пользовательских загрузчиков классов, например, включая апплеты, контейнеры сервлетов и т. Д.) Для поддержки этого необходим некоторый компилятор (или интерпретатор) времени выполнения.Выполнение предварительной компиляции означало бы, что вам придется либо удалить поддержку для этого, либо рассматривать ее как особый случай.

1 голос
/ 30 мая 2016

Более быстрое время запуска и возможность более разумной оптимизации после профилирования кода во время выполнения.

Эта статья дает отличный ответ на этот вопрос: https://advancedweb.hu/2016/05/27/jvm_jit_optimization_techniques/

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

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

Он также может компилировать только тело цикла, если он выполняется так много раз.

1 голос
/ 26 апреля 2011

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

С одной стороны, неизвестно, насколько велика программа. Люди будут очень расстроены при 30-минутном запуске, так как он скомпилирует каждую найденную библиотеку (данная Java-программа не находится в одном файле, она имеет доступ ко всему в пути к классам)

С другой стороны, даже если вы точно сказали системе, какие компоненты будет использовать ваша программа, невозможно сказать, сколько вашей программы можно было бы использовать для данного запуска - люди будут более расстроены при 30-минутном запуске, чтобы запустить программа командной строки с параметрами, состоящими из "--help"

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

public testMeh(int param) {
    if(param == 35) 
        do bunches of crap;
    else if (param > 5)
        do much more crap;
    else 
        return;
    }

Компилятор может вызвать его один или два раза и на лету распознать, что значения 5 и ниже просто возвращаются. Если он вызывается все время со значением 2, он может заменить вызов метода ENTIRE на if (param! = 2) testMeh (param);

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

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

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

...