Перейти к основному содержимому

Введение в JVM Intrinsics

· 5 мин. чтения

1. Введение

В этой статье мы узнаем, что такое встроенные функции и как они работают в Java и других языках на основе JVM.

2. Что такое внутренние качества?

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

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

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

Внутренности могут дать различные преимущества. Замена определенных алгоритмов нативным кодом может повысить их производительность или даже использовать специфические функции операционной системы или базовое оборудование.

3. Внутренности JVM

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

Как именно это работает, зависит от JVM. Сюда входят не только разные версии JVM — например, Java 8 и Java 11. Это также включает в себя различные цели JVM — например, Linux против Windows — и особенно поставщиков JVM — Oracle против IBM. В некоторых случаях на них могут влиять определенные флаги командной строки, переданные JVM.

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

4. Преимущества производительности

Внутренности часто используются для реализации более эффективной версии того же кода , например, путем использования деталей реализации работающей ОС или ЦП. Иногда это связано с тем, что он может использовать более эффективную реализацию, а иногда может зайти так далеко, что использует аппаратно-зависимую функциональность.

Например, HotSpot JDK имеет встроенную реализацию многих методов в java.lang.Math . В зависимости от конкретной JVM они потенциально могут быть реализованы с использованием инструкций ЦП для выполнения необходимых вычислений.

Простой тест продемонстрирует это. Например, возьмем java.lang.Math.sqrt() . Мы можем написать тест:

for (int a = 0; a < 100000; ++a) {
double result = Math.sqrt(a);
}

Этот тест выполняет операцию извлечения квадратного корня 100 000 раз, что занимает примерно 123 мс. Однако, если мы заменим этот код копией реализации Math.sqrt() :

double result = StrictMath.sqrt(a);

Этот код делает то же самое, но вместо этого выполняется за 166 мс. Это увеличение на 35% за счет копирования реализации вместо того, чтобы позволять JVM заменять ее встроенной версией.

5. Невозможные реализации

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

Например, давайте посмотрим на метод onSpinWait() в классе java.lang.Thread . Этот метод указывает, что этот поток в настоящее время не выполняет никакой работы и что процессорное время может быть предоставлено другому потоку. Чтобы реализовать это, он должен работать на самом низком уровне.

HotSpot JDK для архитектур x86 реализует это непосредственно на ЦП, используя код операции PAUSE . Единственным другим способом добиться этого было бы использование вызова JNI к собственному коду, и связанные с этим накладные расходы в первую очередь сводили бы на нет преимущества вызова.

6. Идентификация внутренностей в Java

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

Однако при использовании Hotspot JVM начиная с Java 9 аннотация @HotSpotIntrinsicCandidate используется для всех методов, которые могут быть заменены. Добавление этой аннотации не приводит к автоматической замене метода. На самом деле это происходит в базовой JVM. Вместо этого разработчики JVM знают, что эти методы особенные, и с ними нужно быть осторожными.

Другие JVM могут обрабатывать это по-другому, если они вообще идентифицируются. Это включает JVM Hotspot в Java 8 или более ранней версии.

7. Резюме

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

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