JNA кажется немного проще в использовании для вызова машинного кода по сравнению с JNI. В каких случаях вы бы использовали JNI вместо JNA?
JNA кажется немного проще в использовании для вызова машинного кода по сравнению с JNI. В каких случаях вы бы использовали JNI вместо JNA?
Ответы:
Вот с какими проблемами я столкнулся. Может быть, есть еще кое-что. Но в целом производительность jna и jni не так уж сильно отличается, поэтому используйте ее везде, где вы можете использовать JNA.
РЕДАКТИРОВАТЬ
Этот ответ кажется довольно популярным. Итак, вот некоторые дополнения:
Итак, я по-прежнему считаю, что везде, где это возможно, лучше использовать JNA или BridJ и вернуться к jni, если производительность критична, потому что, если вам нужно часто вызывать собственные функции, производительность заметна.
JNIEXPORT
функции. В настоящее время я изучаю JavaCpp как вариант, который использует JNI, но я не думаю, что ванильный JNI поддерживает это. Есть ли способ вызвать функции-члены C ++ с использованием ванильного JNI, на который я не обращаю внимания?
На столь общий вопрос сложно ответить. Я полагаю, что наиболее очевидное различие состоит в том, что с JNI преобразование типов реализуется на внутренней стороне границы Java / native, тогда как с JNA преобразование типов реализовано на Java. Если вы уже чувствуете себя достаточно комфортно с программированием на C и вам нужно реализовать собственный код самостоятельно, я бы предположил, что JNI не будет казаться слишком сложным. Если вы программист на Java и вам нужно только вызвать стороннюю собственную библиотеку, использование JNA, вероятно, является самым простым способом избежать, возможно, не столь очевидных проблем с JNI.
Хотя я никогда не проводил сравнительный анализ каких-либо различий, из-за дизайна я бы предположил, по крайней мере, что преобразование типов с помощью JNA в некоторых ситуациях будет работать хуже, чем с JNI. Например, при передаче массивов JNA преобразует их из Java в нативный в начале каждого вызова функции и обратно в конце вызова функции. С помощью JNI вы можете контролировать себя, когда создается собственное "представление" массива, потенциально создавая только представление части массива, сохраняя представление через несколько вызовов функций и, в конце концов, отпустите представление и решите, хотите ли вы сохранить изменения (возможно, потребуется скопировать данные обратно) или отменить изменения (копия не требуется). Я знаю, что вы можете использовать собственный массив для вызовов функций с JNA, используя класс Memory, но это также потребует копирования памяти, что может быть ненужным с JNI. Разница может быть несущественной, но если ваша первоначальная цель - повысить производительность приложения за счет реализации его частей в собственном коде, использование менее производительной технологии моста кажется не самым очевидным выбором.
Это только то, что я могу придумать в голове, хотя я и не являюсь активным пользователем. Также кажется, что вы могли бы избежать JNA, если бы вам нужен лучший интерфейс, чем тот, который они предоставляют, но вы можете кодировать это в java.
Кстати, в одном из наших проектов мы сохранили очень маленький след JNI. Мы использовали буферы протокола для представления наших объектов домена и, таким образом, имели только одну встроенную функцию для соединения Java и C (тогда, конечно, эта функция C вызывала бы множество других функций).
Это не прямой ответ, и у меня нет опыта работы с JNA, но когда я смотрю на проекты, использующие JNA и вижу такие имена, как SVNKit, IntelliJ IDEA, NetBeans IDE и т. Д., Я склонен полагать, что это довольно приличная библиотека.
На самом деле, я определенно думаю, что использовал бы JNA вместо JNI, когда мне было нужно, поскольку он действительно выглядит проще, чем JNI (у которого скучный процесс разработки). Жаль, что JNA в это время не была выпущена.
Если вам нужна производительность JNI, но вас пугает ее сложность, вы можете рассмотреть возможность использования инструментов, которые автоматически генерируют привязки JNI. Например, JANET (отказ от ответственности: это я написал) позволяет вам смешивать код Java и C ++ в одном исходном файле и, например, выполнять вызовы из C ++ в Java, используя стандартный синтаксис Java. Например, вот как вы должны вывести строку C в стандартный вывод Java:
native "C++" void printHello() {
const char* helloWorld = "Hello, World!";
`System.out.println(#$(helloWorld));`
}
Затем JANET переводит Java со встроенной обратной кавычкой в соответствующие вызовы JNI.
Я действительно провел несколько простых тестов с JNI и JNA.
Как уже отмечали другие, JNA предназначена для удобства. При использовании JNA вам не нужно компилировать или писать собственный код. Загрузчик собственных библиотек JNA также является одним из лучших / самых простых в использовании, которые я когда-либо видел. К сожалению, похоже, вы не можете использовать его для JNI. (Вот почему я написал альтернативу для System.loadLibrary () которая использует соглашение о путях JNA и поддерживает бесшовную загрузку из пути к классам (т.е. jar-файлов).)
Однако производительность JNA может быть намного хуже, чем у JNI. Я провел очень простой тест, который вызвал простую встроенную функцию целочисленного приращения «return arg + 1;». Тесты, проведенные с помощью jmh, показали, что вызовы этой функции JNI в 15 раз быстрее, чем JNA.
Более «сложный» пример, где собственная функция суммирует целочисленный массив из 4 значений, все же показал, что производительность JNI в 3 раза выше, чем у JNA. Уменьшенное преимущество, вероятно, связано с тем, как вы получаете доступ к массивам в JNI: в моем примере были созданы некоторые вещи и снова выпущены во время каждой операции суммирования.
Код и результаты тестирования можно найти на github .
Я исследовал JNI и JNA для сравнения производительности, потому что нам нужно было выбрать один из них для вызова dll в проекте, а у нас было ограничение по времени. Результаты показали, что JNI имеет большую производительность, чем JNA (примерно в 40 раз). Возможно, в JNA есть способ повысить производительность, но для простого примера он очень медленный.
Если я чего-то не упускаю, разве главное отличие JNA от JNI в том, что с JNA вы не можете вызывать Java-код из собственного (C) кода?
В моем конкретном приложении JNI оказалось намного проще использовать. Мне нужно было читать и записывать непрерывные потоки в последовательный порт и из него - и ничего больше. Вместо того, чтобы пытаться изучить очень сложную инфраструктуру в JNA, я обнаружил, что намного проще прототипировать собственный интерфейс в Windows с помощью специальной DLL, которая экспортирует всего шесть функций: