¿Usar JNI en lugar de JNA para llamar al código nativo?


JNA parece un poco más fácil de usar para llamar a código nativo en comparación con JNI. ¿En qué casos usarías JNI sobre JNA?

Author: Marcus Leon, 2009-10-12

9 answers

  1. JNA no admite la asignación de clases de c++, por lo que si está utilizando la biblioteca de c++ necesitará un contenedor jni
  2. Si necesita mucha copia de memoria. Por ejemplo, llamas a un método que te devuelve un búfer de bytes grande, cambias algo en él, luego necesitas llamar a otro método que usa este búfer de bytes. Esto requeriría copiar este búfer de c a java, luego copiarlo de nuevo de java a c. En este caso, jni ganará en rendimiento porque puede mantener y modificar este búfer en c, sin copiar.

Estos son los problemas que he encontrado. Tal vez haya más. Pero en general, el rendimiento no es tan diferente entre jna y jni, así que donde quiera que pueda usar JNA, úselo.

EDITAR

Esta respuesta parece ser bastante popular. Así que aquí hay algunas adiciones:

  1. Si necesita mapear C++ o COM, hay una biblioteca de Oliver Chafic, creador de JNAerator, llamada BridJ. Todavía es una biblioteca joven, pero tiene muchas características interesantes:
    • Dynamic C / C++ / COM interop: llama a métodos de C++, crea objetos de C++ (y subclases de clases de C++ desde Java!)
    • Asignaciones de tipos sencillas con buen uso de genéricos (incluido un modelo mucho más agradable para Punteros)
    • Soporte completo de JNAerator
    • funciona en Windows, Linux, macOS X, Solaris, Android
  2. En cuanto a la copia de memoria, creo que JNA admite ByteBuffers directos, por lo que la copia de memoria puede ser evitar.

Por lo tanto, todavía creo que siempre que sea posible, es mejor usar JNA o BridJ, y volver a jni si el rendimiento es crítico, porque si necesita llamar a funciones nativas con frecuencia, el rendimiento es notable.

 120
Author: Denis Tulskiy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-19 12:18:12

Es difícil responder a una pregunta tan genérica. Supongo que la diferencia más obvia es que con JNI, la conversión de tipos se implementa en el lado nativo del borde Java/nativo, mientras que con JNA, la conversión de tipos se implementa en Java. Si ya te sientes bastante cómodo con la programación en C y tienes que implementar algún código nativo tú mismo, asumiría que JNI no parecerá demasiado complejo. Si usted es un programador Java y solo necesita invocar una biblioteca nativa de terceros, usar JNA es probablemente el camino más fácil para evitar los problemas quizás no tan obvios con JNI.

Aunque nunca he comparado ninguna diferencia, debido al diseño, al menos supongo que la conversión de tipos con JNA en algunas situaciones funcionará peor que con JNI. Por ejemplo, al pasar matrices, JNA las convertirá de Java a nativas al principio de cada llamada a función y al final de la llamada a función. Con JNI, puede controlarse cuando una "vista nativa" de la matriz se genera, potencialmente solo la creación de una vista de una parte de la matriz, mantener la vista a través de varias llamadas a funciones y al final liberar la vista y decidir si desea mantener los cambios (potencialmente requiere copiar los datos de nuevo) o descartar los cambios (no se requiere copia). Sé que puede usar una matriz nativa a través de llamadas de función con JNA usando la clase de memoria, pero esto también requerirá copia de memoria, lo que puede ser innecesario con JNI. La diferencia puede no ser relevante, pero si su objetivo original es aumentar el rendimiento de la aplicación mediante la implementación de partes de la misma en código nativo, el uso de una tecnología de puente de peor rendimiento no parece ser la opción más obvia.

 29
Author: jarnbjo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-10-12 20:31:58
  1. Está escribiendo código hace unos años antes de que existiera JNA o está apuntando a un JRE pre 1.4.
  2. El código con el que está trabajando no está en una DLL\SO.
  3. Está trabajando en código que es incompatible con LGPL.

Eso es solo lo que se me ocurre en la cabeza, aunque no soy un usuario pesado de ninguno de los dos. También parece que podría evitar JNA si quisiera una mejor interfaz que la que proporcionan, pero podría codificar alrededor de eso en java.

 8
Author: stonemetal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-10-12 20:03:03

Por cierto, en uno de nuestros proyectos, mantuvimos una huella JNI muy pequeña. Usamos búferes de protocolo para representar nuestros objetos de dominio y, por lo tanto, solo teníamos una función nativa para unir Java y C (entonces, por supuesto, esa función C llamaría a un montón de otras funciones).

 7
Author: Ustaman Sangat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-12-14 16:09:35

No es una respuesta directa y no tengo experiencia con JNA, pero cuando miro los Proyectos que usan JNA y veo nombres como SVNKit, IntelliJ IDEA, NetBeans IDE, etc., tiendo a creer que es una biblioteca bastante decente.

En realidad, definitivamente creo que habría usado JNA en lugar de JNI cuando tuve que hacerlo, ya que de hecho parece más simple que JNI (que tiene un proceso de desarrollo aburrido). Lástima, JNA no fue liberado en este momento.

 5
Author: Pascal Thivent,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-10-12 20:04:12

Si desea un rendimiento JNI pero se siente intimidado por su complejidad, puede considerar el uso de herramientas que generen enlaces JNI automáticamente. Por ejemplo, JANET (descargo de responsabilidad: Yo lo escribí) le permite mezclar código Java y C++ en un solo archivo fuente, y por ejemplo, hacer llamadas desde C++ a Java utilizando la sintaxis estándar de Java. Por ejemplo, así es como imprimirías una cadena C a la salida estándar de Java:

native "C++" void printHello() {
    const char* helloWorld = "Hello, World!";
    `System.out.println(#$(helloWorld));`
}

JANET luego traduce el backtick-embedded Java en el JNI apropiado llamada.

 3
Author: Dawid Kurzyniec,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-28 09:02:50

Investigué JNI y JNA para la comparación de rendimiento porque necesitábamos decidir que uno de ellos llamara a un dll en el proyecto y teníamos una restricción de tiempo real. Los resultados han demostrado que el JNI tiene un mayor rendimiento que el JNA (aproximadamente 40 veces). Tal vez hay un truco para un mejor rendimiento en JNA, pero es muy lento para un ejemplo simple.

 2
Author: Mustafa Kemal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-08-06 14:04:29

En realidad hice algunos puntos de referencia simples con JNI y JNA.

Como otros ya señalaron, el JNA es por conveniencia. No es necesario compilar o escribir código nativo cuando se utiliza JNA. El cargador de bibliotecas nativo de JNA también es uno de los mejores y más fáciles de usar que he visto. Lamentablemente, parece que no se puede usar para el JNI. (Es por eso que escribí una alternativa para el Sistema.LoadLibrary () que utiliza la convención path de JNA y soporta la carga continua desde classpath (ie frasco).)

El rendimiento del JNA sin embargo, puede ser mucho peor que el del JNI. Hice una prueba muy simple que llamó a una función de incremento de entero nativo simple " return arg + 1;". Los puntos de referencia realizados con jmh mostraron que las llamadas JNI a esa función son 15 veces más rápidas que JNA.

Un ejemplo más "complejo" donde la función nativa resume un array entero de 4 valores todavía mostró que el rendimiento de JNI es 3 veces más rápido que JNA. La ventaja reducida fue probablemente debido a cómo arrays de acceso en JNI: mi ejemplo creó algunas cosas y las liberó de nuevo durante cada operación de suma.

El código y los resultados de las pruebas se pueden encontrar en github.

 2
Author: user1050755,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-14 14:29:26

A menos que me falte algo, ¿no es la principal diferencia entre JNA vs JNI que con JNA no se puede llamar código Java desde código nativo (C)?

 1
Author: Augusto,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-03-17 22:32:51