В чем разница между встроенными и нативными методами Java? - PullRequest
5 голосов
/ 21 июня 2019

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

В чем разница?

Ответы [ 3 ]

7 голосов
/ 21 июня 2019

Основное отличие состоит в том, что JVM знает о реализации встроенного метода и может заменить исходный java-код машинно-зависимыми хорошо оптимизированными инструкциями (иногда даже с одной инструкцией процессора), тогда какреализация метода JNI неизвестна для JVM.

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

PS Предоставленная вами ссылка содержитсписок известных методов для этой конкретной JVM.Этот список может отличаться от одной JVM к другой.

6 голосов
/ 21 июня 2019

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

Функция JNI - это 100% черный ящик для компилятора со значительными накладными расходами на вызов / возврат (особенно, если вы используете его только для скаляра).

Но даже если бы это был просто вызов такой функции, как int bitcount(unsigned x){ return __builtin_popcount(x); }, скомпилированной в x86-64 popcnt eax, edi; ret (x86-64 Соглашение о вызовах System V) вызывающей стороне (которую излучает JIT-компилятор) все равно придется предполагать, что все регистры с вызовом были заблокированы. На x86-64 это большая часть целочисленных регистров и всех регистров FP / вектора. (Точно так же, как стоимость преждевременного компилятора C ++ для вызова функции черного ящика вместо встроенной). Но я подозреваю, что стоимость вызова функции JNI включает в себя некоторые дополнительные издержки.

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

Кроме того, внутренние свойства означают, что JVM понимает , что делает функция, и может оптимизировать ее. например при постоянном распространении он знает, что popcount (5) = 2 установленных бита. Но с фактической функцией JNI она все равно должна вызывать ее. И каждый вызов является видимым побочным эффектом, если только не существует способа объявить функцию «чистой», чтобы она могла CSE.

При сильном встраивании постоянные времени компиляции не редкость.

4 голосов
/ 21 июня 2019

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

native - это метод, который объявлен как native в исходном коде Java класса.

«Встроенный» метод - это метод, для которого среда выполнения JVM (в частности, JIT-компилятор) выполняет специальную оптимизацию.Одна из вещей, которая означает «внутренняя», заключается в том, что последовательность вызовов не является вызовом JNI.Но оптимизации могут быть более обширными, чем это.

Обратите внимание, что native и "intrisic" являются ортогональными:

  • Метод может быть как native, так и "intrinsic";например arraycopy.Метод, который является одновременно native и "внутренним", (как правило) не будет реализован как метод JNI.
  • Метод может быть "внутренним", не будучи native;например, некоторые String методы в некоторых версиях Java.В этом случае исходный код Java и его байт-коды игнорируются в JIT-скомпилированной версии метода.

Это похоже на метод JNI, который также является блокомнативный код.

JNI - это API для реализации native методов, которые не являются «внутренними».Таким образом, метод JNI - это метод, реализованный в C / C ++, с сигнатурой, совместимой с вызывающей последовательностью JNI.

Проблема состоит в том, что последовательность вызова метода JNI имеет больший вес, чем типичный Java-to-Java или внутренняя последовательность вызова Java.(Это связано с общим характером вызова JNI и необходимостью проверять и отображать аргументы / результаты между Java соответствующими типами C / C ++ ... и тому подобными вещами.)

Другая проблема с JNIметоды по сравнению с Java и встроенные методы таковы, что JIT-компилятор не знает, что делают первые, и поэтому не может применять различные оптимизации через границу вызова;например, встраивание.

...