Во-первых, стоит отметить, что под «медленным» мы говорим о чем-то, что может занять десятки наносекунд. Для простых тривиальных методов в 2010 году я измерил вызовы в среднем на 40 нс на моем рабочем столе Windows и 11 нс на моем рабочем столе Mac. Если вы не делаете много звонков, вы не будете замечать.
Тем не менее, вызов нативного метода может быть медленнее , чем обычный вызов метода Java. Причины включают в себя:
- Собственные методы не будут встроены JVM. И при этом они не будут точно скомпилированы для этой конкретной машины - они уже скомпилированы.
- Массив Java может быть скопирован для доступа в нативный код, а затем скопирован обратно. Стоимость может быть линейной по размеру массива. Я измерил JNI , копирующий массива 100 000, в среднем около 75 микросекунд на моем рабочем столе Windows и 82 микросекунд на Mac. К счастью, прямой доступ может быть получен через GetPrimitiveArrayCritical или NewDirectByteBuffer .
- Если методу передан объект или ему необходимо выполнить обратный вызов, то нативный метод, скорее всего, будет делать свои собственные вызовы JVM. Доступ к полям, методам и типам Java из нативного кода требует чего-то похожего на рефлексию. Подписи указываются в строках и запрашиваются в JVM. Это медленный и подвержен ошибкам.
- Строки Java являются объектами, имеют длину и кодируются. Для доступа к строке или ее создания может потребоваться копия O (n).
Некоторое дополнительное обсуждение, возможно, датированное, можно найти в статье «Производительность платформы Java: стратегии и тактики», 2000 г., Стив Уилсон и Джефф Кессельман, в разделе «9.2: Изучение затрат JNI». Это примерно треть пути вниз этой страницы , предоставленной в комментарии @Philip ниже.
Документ IBM developerWorks 2009 года "Лучшие практики использования собственного интерфейса Java" содержит некоторые предложения по предотвращению ошибок производительности с JNI.