Использовать JNI вместо JNA для вызова собственного кода?

JNA кажется более легким в использовании для вызова собственного кода по сравнению с JNI. В каких случаях вы бы использовали JNI над JNA?

    9 Solutions collect form web for “Использовать JNI вместо JNA для вызова собственного кода?”

    1. JNA не поддерживает отображение classов c ++, поэтому, если вы используете библиотеку c ++, вам понадобится jni-обертка
    2. Если вам нужно много копирования памяти. Например, вы вызываете один метод, который возвращает вам большой байтовый буфер, вы что-то меняете в нем, тогда вам нужно вызвать другой метод, который использует этот байтовый буфер. Это потребует, чтобы вы скопировали этот буфер с c на java, а затем скопировали его с java на c. В этом случае jni победит в производительности, потому что вы можете сохранить и изменить этот буфер в c, без копирования.

    Это проблемы, с которыми я столкнулся. Возможно, их больше. Но в целом производительность не отличается от jna и jni, поэтому везде, где вы можете использовать JNA, используйте ее.

    РЕДАКТИРОВАТЬ

    Этот ответ кажется довольно популярным. Итак, вот некоторые дополнения:

    1. Если вам нужно отобразить C ++ или COM, есть библиотека от Oliver Chafic, создателя JNAerator, называемого BridJ . Это еще молодая библиотека, но у нее много интересных особенностей:
      • Динамический интерфейс C / C ++ / COM: вызовите методы C ++, создайте объекты C ++ (и classы подclassа C ++ из Java!)
      • Прямолинейные отображения с хорошим использованием дженериков (в том числе гораздо более приятная модель для указателей)
      • Полная поддержка JNAerator
      • работает на Windows, Linux, MacOS X, Solaris, Android
    2. Что касается копирования памяти, я считаю, что JNA поддерживает прямой ByteBuffers, поэтому копирования памяти можно избежать.

    Итак, я по-прежнему считаю, что, когда это возможно, лучше использовать JNA или BridJ и вернуться к jni, если производительность критическая, потому что, если вам нужно часто называть собственные функции, поражение производительности заметно.

    Трудно ответить на такой общий вопрос. Я полагаю, что наиболее очевидным отличием является то, что с JNI преобразование типов реализовано на родной стороне Java / родной границы, а с JNA преобразование типов реализовано на Java. Если вы уже чувствуете себя вполне комфортно с программированием на C и должны сами реализовать собственный код, я бы предположил, что JNI не будет казаться слишком сложным. Если вы программист на Java и вам нужно только вызывать стороннюю библиотеку, использование JNA, вероятно, является самым простым путем, чтобы избежать, возможно, не столь очевидных проблем с JNI.

    Хотя я никогда не сравнивал какие-либо различия, я бы из-за дизайна, по крайней мере, предположил, что преобразование типа с JNA в некоторых ситуациях будет хуже, чем с JNI. Например, при передаче массивов JNA будет преобразовывать их из Java в native в начале каждого вызова функции и обратно в конце вызова функции. С JNI вы можете управлять собой, когда генерируется собственное «представление» массива, потенциально только создавая представление о части массива, сохраняя представление по нескольким вызовам функций и в конце релиза представления и решая, хотите ли вы сохранить изменения (возможно, потребовать, чтобы скопировать данные назад) или отказаться от изменений (без необходимости копирования). Я знаю, что вы можете использовать собственный массив для вызовов функций с помощью JNA с использованием classа памяти, но для этого также потребуется копирование памяти, что может быть ненужным с JNI. Разница может быть неактуальной, но если ваша первоначальная цель – увеличить производительность приложения, реализовав ее части в собственном коде, использование хуже используемой мостовой технологии, по-видимому, не является самым очевидным выбором.

    1. Вы пишете код несколько лет назад, прежде чем появилась JNA или нацелились на pre 1.4 JRE.
    2. Код, с которым вы работаете, не находится в DLL \ SO.
    3. Вы работаете над кодом, который несовместим с LGPL.

    Это только то, что я могу придумать с головы, хотя я тоже не тяжелый пользователь. Также кажется, что вы можете избежать JNA, если вам нужен лучший интерфейс, чем тот, который они предоставляют, но вы можете кодировать его в java.

    Кстати, в одном из наших проектов мы сохранили очень маленький отпечаток JNI. Мы использовали протокольные буферы для представления наших доменных объектов и, следовательно, имели только одну нативную функцию для переноса Java и C (тогда, конечно, функция C вызовет множество других функций).

    Это не прямой ответ, и у меня нет опыта работы с JNA, но когда я смотрю проекты с использованием JNA и вижу такие имена, как SVNKit, IntelliJ IDEA, IDE NetBeans и т. Д., Я склонен считать, что это довольно приличная библиотека.

    На самом деле, я определенно думаю, что использовал бы 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 для сравнения производительности, потому что нам нужно было решить, чтобы один из них вызывал DLL в проекте, и у нас было ограничение в реальном времени. Результаты показали, что JNI имеет большую производительность, чем JNA (примерно 40 раз). Может быть, есть трюк для лучшей производительности в JNA, но для простого примера это очень медленно.

    На самом деле я сделал несколько простых тестов с JNI и JNA.

    Как уже указывали другие, JNA для удобства. При использовании JNA вам не нужно компилировать или писать собственный код. Собственный загрузчик библиотеки JNA также является одним из лучших / самых простых в использовании, которые я когда-либо видел. К сожалению, вы не можете использовать его для JNI. (Вот почему я написал альтернативу для System.loadLibrary (), которая использует соглашение о трассировке JNA и поддерживает бесшовную загрузку из пути к classам (например, банки).)

    Однако производительность JNA может быть намного хуже, чем у JNI. Я сделал очень простой тест, который называется простой нативной целочисленной функцией increment «return arg + 1;». Тесты, выполненные с помощью jmh, показали, что JNI вызывает эту функцию в 15 раз быстрее, чем JNA.

    Более «сложный» пример, когда нативная функция суммирует целочисленный массив из 4 значений, все еще показывает, что производительность JNI в 3 раза выше, чем у JNA. Сниженное преимущество, вероятно, было связано с тем, как вы получаете доступ к массивам в JNI: мой пример создал некоторые вещи и снова выпустил их во время каждой операции суммирования.

    Код и результаты тестов можно найти в github .

    Если я что-то не хватает, не главное отличие JNA от JNI от того, что с JNA вы не можете вызывать код Java из native (C) кода?

    Давайте будем гением компьютера.