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