Что делает вызовы JNI медленными?

Я знаю, что «пересечение границ» при вызове JNI в Java происходит медленно.

Однако я хочу знать, что делает его медленным? Что делает базовая реализация jvm при выполнении вызова JNI, который делает его настолько медленным?


person pdeva    schedule 08.10.2011    source источник
comment
(+1) Хороший вопрос. Раз уж мы заговорили об этой теме, я хотел бы призвать всех, кто проводил реальные тесты, опубликовать свои выводы.   -  person NPE    schedule 08.10.2011
comment
Вызов JNI должен преобразовать переданные объекты Java в то, что (например) может понять C; то же самое с возвращаемым значением. Преобразование типов и сортировка стека вызовов - хорошая часть этого.   -  person Dave Newton    schedule 08.10.2011
comment
Дэйв, я понимаю и слышал об этом раньше. Но как точно происходит преобразование? что это за «что-то»? Ищу подробности.   -  person pdeva    schedule 08.10.2011
comment
Использование прямых ByteBuffers для передачи данных между Java и C может привести к относительно низким накладным расходам.   -  person Peter Lawrey    schedule 08.10.2011
comment
для вызова требуется правильный фрейм стека C, выталкивая все полезные регистры ЦП (и выталкивая их обратно), вызов требует ограждения, а также предотвращает множество оптимизаций, таких как встроенная. Также потоки должны покинуть блокировку стека выполнения (например, чтобы позволить смещенным блокировкам работать в машинном коде), а затем получить ее обратно.   -  person bestsss    schedule 09.10.2011


Ответы (3)


Во-первых, стоит отметить, что под медленным мы говорим о чем-то, что может занять десятки наносекунд. Для тривиальных нативных методов в 2010 году я измерил время вызовов в среднем 40 нс на рабочем столе Windows и 11 нс на рабочем столе Mac. Если вы не сделаете много звонков, вы этого не заметите.

При этом вызов собственного метода может быть медленнее, чем вызов обычного метода Java. Причины включают:

  • Собственные методы не будут встроены JVM. И они не будут скомпилированы точно в срок для этой конкретной машины - они уже скомпилированы.
  • Массив Java может быть скопирован для доступа в машинном коде, а затем скопирован обратно. Стоимость может быть линейной в зависимости от размера массива. Я измерил, что JNI копирует массива 100 000 в среднем около 75 микросекунд на моем рабочем столе Windows и 82 микросекунды на Mac. К счастью, прямой доступ можно получить через GetPrimitiveArray или NewDirectByteBuffer.
  • Если методу передается объект или ему необходимо выполнить обратный вызов, то собственный метод, скорее всего, будет делать свои собственные вызовы JVM. Доступ к полям, методам и типам Java из нативного кода требует чего-то похожего на отражение. Подписи указываются в строках и запрашиваются из JVM. Это и медленно, и , и подвержено ошибкам.
  • Строки Java являются объектами, имеют длину и закодированы. Для доступа к строке или ее создания может потребоваться O (n) копия.

Некоторое дополнительное обсуждение, возможно датированное, можно найти в книге Java (tm) Platform Performance: Strategies and Tactics, 2000, Стива Уилсона и Джеффа Кессельмана, в разделе 9.2: Исследование затрат JNI. Это примерно треть пути вниз этого страница, предоставленная в комментарии @Philip ниже.

В документе «Лучшие практики использования собственного интерфейса Java» IBM developerWorks за 2009 г. несколько советов по предотвращению ошибок производительности с помощью JNI.

person Andy Thomas    schedule 18.10.2011
comment
В этом ответе утверждается, что некоторый собственный код может быть встроен JVM. - person A.H.; 19.10.2011
comment
В этом ответе отмечается, что некоторый стандартный собственный код встроен в JVM, а не использует JNI. Выше, собственные методы относятся к общему случаю определяемых пользователем собственных методов, реализованных через JNI. Спасибо за указатель на sun.misc.Unsafe. - person Andy Thomas; 19.10.2011
comment
Я не хотел утверждать, что этот подход можно использовать для каждого вызова JNI. Но не повредит знать, что существует некая золотая середина между чистым байт-кодом и чистым кодом JNI. Возможно, это повлияет на некоторые дизайнерские решения. Возможно, этот механизм будет обобщен в будущем. - person A.H.; 19.10.2011
comment
Я награждаю этот ответ наградой, но оставляю вопрос «открытым», чтобы привлечь всех, кто хочет дать еще более подробный ответ. - person pdeva; 20.10.2011
comment
@ A.H, вы ошиблись внутренним w / JNI. Они совсем другие. sun.misc.Unsafe и множество других вещей, таких как System.currentTimeMillis/nanoTime, обрабатываются JVM с помощью «магии». Они не являются JNI, и у них вообще нет надлежащих файлов .c / .h, за исключением самой JVM. Этого подхода нельзя придерживаться, если вы не пишете / не взламываете JVM. - person bestsss; 18.01.2012
comment
этот документ java.sun.com является в настоящее время не работает - здесь Вот ссылка рабочая. - person Philip Guin; 05.01.2014
comment
@Philip - Спасибо, обновили текст выше своей ссылкой. - person Andy Thomas; 29.07.2014

Следует отметить, что не все методы Java, отмеченные знаком native, являются «медленными». Некоторые из них являются внутренними функциями, что делает их чрезвычайно быстрыми. Чтобы проверить, какие из них являются внутренними, а какие нет, вы можете найти do_intrinsic по адресу vmSymbols.hpp.

person Tema    schedule 15.07.2012

В основном JVM интерпретирующе конструирует параметры C для каждого вызова JNI, и код не оптимизируется.

Более подробная информация представлена ​​в этот документ

Если вы заинтересованы в тестировании JNI и нативного кода, в этом проекте есть код для выполнения тестов.

person dmck    schedule 08.10.2011
comment
документ, на который вы ссылаетесь, больше похож на документ с тестами производительности, чем на тот, который описывает внутреннюю работу JNI. - person pdeva; 08.10.2011
comment
@pdeva К сожалению, другие ресурсы, которые я нашел, были связаны с java.sun.com, и эти ссылки не обновлялись с момента приобретения Oracle. Я ищу более подробную информацию о внутренностях JNI. - person dmck; 08.10.2011
comment
Статья посвящена Java 1.3 - довольно давно. Относятся ли проблемы того времени к Java 7? - person A.H.; 08.10.2011