Что делает последние версии JVM быстрее? - программирование
Подтвердить что ты не робот

Что делает последние версии JVM быстрее?

Недавно я видел несколько заявлений о том, как Java (и JVM-языки, такие как Scala) сопоставимы по производительности с C/С++-кодом.

Например, из описания проекта ScalaLab:

Скорость Scala на основе сценариев, которая приближается к скорости собственный и оптимизированный Java-код, и, таким образом, близок или даже лучше из научного кода на основе C/С++!

Может ли кто-нибудь указать мне, что такое оптимизация JVM? Существуют ли какие-либо реальные ориентиры, подтверждающие это утверждение или предоставляющие какое-либо сравнение в реальном мире?

4b9b3361

Ответ 1

Методы производительности

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

Для этого JVM этот список из внутренней вики HotSpot обеспечивает отличный старт (и дочерние страницы подробно описывают некоторые из более интересные техники). Если вы просто ищете список трюков для прачечной, у wiki это тоже есть, хотя, чтобы понять их, вам, вероятно, придется google отдельные термины.

Не все из них были реализованы в последнее время, но некоторые из них имеют (разрешение проверки пробелов, анализ побега, оптимизацию суперслова) - по крайней мере, для свободного определения "недавно".

Далее рассмотрим относительную картину производительности, когда дело доходит до C/С++ vs Java, и почему методы, описанные выше, помогают либо сократить разрыв, либо в некоторых случаях фактически дают Java и внутреннее преимущество по сравнению с родными языками.

Java vs C/С++

На высоком уровне оптимизация представляет собой сочетание вещей, которые вы увидите в любом достойном компиляторе для таких родных языков, как C и С++, а также вещи, необходимые для снижения воздействия специфических функций Java и JVM и безопасности проверки, например:

  • Анализ Escape, который уменьшает (несколько) распределение стека без объектов
  • Встроенные кэши и анализ иерархии классов, которые уменьшают "каждая функция является виртуальной"
  • Исправление диапазона проверки, которое уменьшает "каждый доступ к массиву проверяется диапазоном"

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

  • Динамическая вставка только самого горячего кода
  • Генерация кода на основе фактических частот ветвления/коммутатора
  • Динамическая генерация кода с поддержкой кода/инструкций (даже функции ЦП, выпущенные после компиляции кода!) 1
  • Элисон никогда не исполняемого кода
  • Ввод инструкций предварительной выборки, чередующихся с кодом приложения
  • Вся совокупность методов, поддерживаемых safepointing

Консенсус, похоже, заключается в том, что Java часто создает код, похожий по скорости, на хорошие компиляторы С++ на умеренном уровне оптимизации, например gcc-O2, хотя многое зависит от точного эталона. Современные JVM, такие как HotSpot, стремятся преуспеть при обходе массива низкого уровня и математике (пока конкурирующий компилятор не вектурирует - это трудно превзойти) или в сценариях с распределением тяжелых объектов, когда конкурирующий код выполняет аналогичное количество распределений (Распределение объектов JVM + GC, как правило, быстрее, чем malloc), но падает, когда ограничение памяти для типичных приложений Java является фактором, когда распределение стека в значительной степени используется или где векторизация компиляторов или внутренних процессоров подсказывает масштабы в соответствии с собственным кодом.

Если вы ищете производительность Java против C, вы найдете множество людей, которые решали этот вопрос с разной степенью строгости. Здесь сначала я наткнулся на, что, похоже, показывает грубую связь между gcc и HotSpot (даже при -O3 в этом случае). Это сообщение и связанные обсуждения, вероятно, лучше начать, если вы хотите увидеть, как один тест может пройти через несколько итераций на каждом языке, перескочить друг друга - и показывает некоторые пределы оптимизации с обеих сторон.

* не совсем JVM-specific - большинство из них также применимо к другим безопасным или управляемым языкам, таким как CLR


1 Эта особая оптимизация становится все более актуальной как новые наборы инструкций (в частности, инструкции SIMD, но есть others) выпускаются с некоторой частотой. Автоматическая векторизация может ускорить некоторые коды в массовом порядке, а в то время как Java была медленной с точки зрения здесь, они, по крайней мере, догоняют немного.

Ответ 2

Фактическое исполнение курса зависит от эталонных показателей и отличается по заявке. Но легко видеть, как JIT VM могут быть столь же быстрыми, как статически скомпилированный код, по крайней мере теоретически.

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

Другой пример - оптимизация на основе значений времени выполнения. В C/С++ вы используете макрос препроцессора для отключения утверждений и должны перекомпилировать, если вы хотите изменить этот параметр. В Java утверждения обрабатываются путем установки частного логического поля, а затем помещают ветвь if в код. Но так как виртуальная машина может скомпилировать версию кода, которая включает или не включает код подтверждения в зависимости от значения флага, мало или вообще нет производительности.

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

Статический компилятор, конечно, не может этого сделать. Мощный статический анализ доводит вас до сих пор. Это не ограничивается только Java, хотя это самый очевидный пример. Google V8 vm для Javascript также довольно быстро. Pypy стремится сделать то же самое для Python и Rubinius для Ruby, но они не совсем там (это помогает, когда у вас есть большая корпорация, поддерживающая вас).

Ответ 3

Я бы добавил, что hotspot, jrockit и IBM JVM выполняют сжатие кучи в GC. По этой причине я недавно портировал некоторый тяжелый математический код на Scala. Если вы намереваетесь запустить какое-либо большое приложение, я бы настоятельно рекомендовал Java. Вы можете пожаловаться на использование CLR при развертывании на сервере или масштабировании, особенно если интенсивность его памяти.

Также в отношении собственного кода параметры конфигурации JVM превосходны.