9 ответов:
- JNA не поддерживает сопоставление классов c++, поэтому, если вы используете библиотеку c++, вам понадобится оболочка jni
- Если вам нужно много копировать памяти. Например, вы вызываете один метод, который возвращает вам большой байтовый буфер, вы что-то в нем меняете, затем вам нужно вызвать другой метод, который использует этот байтовый буфер. Это потребует от вас скопировать этот буфер с c на java, а затем скопировать его обратно с java на c. в этом случае jni выиграет в производительности, потому что вы можете сохранить и изменить этот буфер в C, без копирования.
вот с какими проблемами я столкнулся. Может быть, это еще не все. Но в целом производительность не так уж отличается между jna и jni, поэтому везде, где вы можете использовать JNA, используйте его.
EDIT
этот ответ, кажется, довольно популярны. Итак, вот некоторые дополнения:
- Если вам нужно сопоставить C++ или COM, есть библиотека Оливера Чафика, создателя JNAerator, под названием BridJ. Это еще молодая библиотека, но она имеет много интересных особенностей:
- динамическое взаимодействие C / C++ / COM: вызовите методы C++, создайте объекты C++ (и подклассы классов C++ из Java!)
- простые сопоставления типов с хорошим использованием дженериков (включая гораздо более приятную модель для указателей)
- полная поддержка JNAerator
- работает на Windows, Linux, MacOS X, Solaris, Android
- Что касается памяти копирование, я считаю, что JNA поддерживает прямые ByteBuffers, поэтому копирование памяти можно избежать.
Итак, я по-прежнему считаю, что везде, где это возможно, лучше использовать JNA или BridJ, и вернуться к jni, если производительность критична, потому что если вам нужно часто вызывать собственные функции, производительность хит заметна.
трудно ответить на такой общий вопрос. Я полагаю, что наиболее очевидным отличием является то, что с JNI преобразование типов реализовано на родной стороне границы Java/native, в то время как с JNA преобразование типов реализовано на Java. Если вы уже чувствуете себя вполне комфортно с программированием на C и должны реализовать некоторый собственный код, я бы предположил, что JNI не будет казаться слишком сложным. Если вы программист Java и вам нужно только вызвать стороннюю собственную библиотеку, использование JNA, вероятно, самый простой способ избежать, возможно, не столь очевидных проблем с JNI.
хотя я никогда не сравнивал никаких различий, я бы из-за дизайна, по крайней мере, предположил, что преобразование типа с JNA в некоторых ситуациях будет работать хуже, чем с JNI. Например, при передаче массивов JNA преобразует их из Java в native в начале каждого вызова функции и обратно в конце вызова функции. С JNI, вы можете контролировать себя, когда родной "представление" массива генерируется, потенциально только создавая представление части массива, сохраняя представление через несколько вызовов функций и в конце отпустите представление и решите, хотите ли вы сохранить изменения (потенциально требующие копирования данных обратно) или отбросить изменения (не требуется копирование). Я знаю, что вы можете использовать собственный массив через вызовы функций с JNA, используя класс памяти, но это также потребует копирования памяти, что может быть ненужным с JNI. Разница может и не быть релевантно, но если ваша первоначальная цель-повысить производительность приложения путем реализации его частей в машинном коде, использование худшей технологии моста кажется не самым очевидным выбором.
- вы пишете код несколько лет назад, прежде чем появилась JNA или нацелены на pre 1.4 JRE.
- код, с которым вы работаете, не находится в DLL\SO.
- вы работаете над кодом, который несовместим с LGPL.
это единственное что я могу придумать с верхней части моей головы, хотя я не являюсь активным пользователем ни. Также кажется, что вы можете избежать JNA, если вам нужен лучший интерфейс, чем тот, который они предоставляют, но вы можете закодировать вокруг этого в Java.
кстати, в одном из наших проектов мы сохранили очень маленький отпечаток ноги JNI. Мы использовали буферы протокола для представления наших объектов домена и, таким образом, имели только одну собственную функцию для моста Java и C (тогда, конечно, эта функция C вызовет кучу других функций).
Это не прямой ответ, и у меня нет опыта работы с JNA, но, когда я смотрю на проекты с использованием JNA и смотрите такие имена, как SVNKit, IntelliJ IDEA, NetBeans IDE и т. д., Я склонен полагать, что это довольно приличная библиотека.
на самом деле, я определенно думаю, что я бы использовал JNA вместо JNI, когда мне пришлось, поскольку это действительно выглядит проще, чем JNI (который имеет скучный процесс разработки). Жаль, что JNA не был освобожден в это время.
Если вы хотите производительность JNI, но устрашены его сложностью, вы можете рассмотреть возможность использования инструментов, которые автоматически генерируют привязки JNI. Например, Дженет (отказ от ответственности: я написал его) позволяет смешивать Java и C++ код в одном исходном файле, и, например, совершать вызовы с C++ на Java с использованием стандартного синтаксиса Java. Например, вот как вы бы напечатали строку C в стандартный вывод Java:
native "C++" void printHello() { const char* helloWorld = "Hello, World!"; `System.out.println(#$(helloWorld));` }Джанет затем переводит встроенный в обратную сторону Java в соответствующие вызовы JNI.
Я исследовал JNI и JNA для сравнения производительности, потому что нам нужно было решить, что один из них вызовет dll в проекте, и у нас было ограничение в реальном времени. Результаты показали, что JNI имеет большую производительность, чем JNA(примерно в 40 раз). Может быть, есть трюк для лучшей производительности в юна, но это очень медленно для простого примера.
Я на самом деле сделал несколько простых тестов с JNI и JNA.
Как уже указывали другие, JNA для удобства. Вам не нужно компилировать или писать собственный код при использовании JNA. Загрузчик собственной библиотеки JNA также является одним из лучших/самых простых в использовании, которые я когда-либо видел. К сожалению, вы не можете использовать его для JNI кажется. (Вот почему я написал Альтернатива для системы.loadLibrary () который использует соглашение о пути JNA и поддерживает бесшовную загрузку из classpath (т. е. файлы jar.))
производительность JNA, однако, может быть намного хуже, чем у JNI. Я сделал очень простой тест, который вызвал простую собственную целочисленную функцию приращения " return arg + 1;". Тесты, выполненные с помощью jmh, показали, что вызовы JNI к этой функции в 15 раз быстрее, чем JNA.
более "сложный" пример, где собственная функция суммирует целочисленный массив из 4 значений, все еще показал, что производительность JNI в 3 раза быстрее, чем JNA. Уменьшенное преимущество было, вероятно, потому, что о том, как вы получаете доступ к массивам в JNI: мой пример создал некоторые вещи и выпустил их снова во время каждой операции суммирования.
код и результаты теста можно найти в github.
Если я чего-то не упускаю, разве это не основное различие между JNA и JNI, что с JNA вы не можете вызвать Java-код из собственного (C) кода?
Comments