Вопросы о возможной оптимизации Java (или другого языка, управляемого памятью) - PullRequest
2 голосов
/ 12 июля 2010

Из того, что я прочитал, java (обычно), похоже, компилирует java для не очень (вообще?) Оптимизированного байт-кода java, оставляя его для оптимизации. Это правда? И если это было какое-либо исследование (возможно, в альтернативных реализациях) получения компилятором для оптимизации кода, чтобы у jit было меньше работы (возможно ли это)?

Кроме того, многим людям не нравится генерация собственного кода (иногда называемая преждевременной компиляцией) для Java (и многих других языков управления памятью высокого уровня) по многим причинам, таким как потеря переносимости (и т. Д.). ), но также отчасти потому, что (по крайней мере, для тех языков, в которых есть компилятор, работающий точно по времени), предполагается, что преждевременная компиляция в машинный код упустит возможные оптимизации, которые могут быть выполнены компилятором jit, и, следовательно, может быть медленнее в долгосрочной перспективе.

Это заставляет меня задаться вопросом, пытался ли кто-нибудь когда-либо реализовывать http://en.wikipedia.org/wiki/Profile-guided_optimization (компиляция в двоичный файл + некоторые дополнительные функции, затем запуск программы и анализ информации о времени выполнения тестового прогона для создания, как мы надеемся, более оптимизированного двоичного файла для использование в реальном мире) для Java / (другие языки, управляемые памятью) и как это можно сравнить с кодом JIT? У кого-нибудь есть подсказка?

Ответы [ 3 ]

4 голосов
/ 13 июля 2010

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

Когда вы запускаете javac, он просматривает только один файл .java, компилируя его в один файл .class. Все реализации интерфейса, виртуальные методы и переопределения проверяются на достоверность, но остаются нерешенными (поскольку невозможно узнать истинные цели вызова метода без анализа всей программы).

JVM использует «загрузку и связывание во время выполнения», чтобы собрать все ваши классы в единую программу (и любой класс в вашей программе может вызывать специализированное поведение для изменения поведения загрузки / связывания по умолчанию).

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

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

2 голосов
/ 21 июля 2010

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

  • для заданных примеров, представляющих, как ваш код фактически используется пользователем или другим кодом.
  • для данной платформы (ЦП, память + другое оборудование, ОС, что угодно).
    С точки зрения производительности, существуют довольно большие различия даже между платформами, которые обычно считаются (более или менее) одинаковыми (например, сравнивают одноядерное старое Athlon с 512M с 6-ядерным процессором Intel с 8G, работающим на Linux, но с очень разные версии ядра).
  • для данной JVM и его конфигурации.

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

Как уже упоминалось, JVM JIT делают что-то очень похожее на профилирование, но делают это на лету. Он также называется «горячей точкой», поскольку он постоянно отслеживает исполняемый код, ищет горячие точки, которые выполняются часто, и пытается оптимизировать только эти части. На этом этапе он сможет использовать больше знаний о коде (зная его контекст, то, как он используется другими классами и т. Д.), Поэтому, как уже упоминалось вами и другими ответами, он может выполнять более эффективные оптимизации как статический Он продолжит мониторинг и, если понадобится, позже выполнит еще один шаг оптимизации, на этот раз попытается еще сложнее (в поисках более дорогой оптимизации).
Работая с реальными данными (статистика использования + платформа + конфигурация), можно избежать оговорок, упомянутых ранее.

Цена - это дополнительное время, которое нужно потратить на «профилирование» + JIT-инг. Большую часть времени он провел довольно хорошо.

Я полагаю, что оптимизатор, управляемый профилем, все еще может конкурировать с ним (или даже превзойти его), но только в некоторых особых случаях, если вы можете избежать предостережений:

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

Это случается редко, и я думаю, что в целом JIT даст вам лучшие результаты, но у меня нет никаких доказательств этого.

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

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

1 голос
/ 21 июля 2010

Официальный компилятор Java Hot Spot выполняет «адаптивную оптимизацию» во время выполнения, что по сути совпадает с упомянутой вами оптимизацией на основе профилей.Это было характерной чертой, по крайней мере, этой конкретной реализации Java в течение долгого времени.

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

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

...