usuario tutorial interfaz gui grafica español ejemplos componentes java jni native jna

java - tutorial - ¿Utiliza JNI en lugar de JNA para llamar al código nativo?



java swing tutorial pdf español (9)

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


  1. Está escribiendo código hace unos años antes de 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 un código que es incompatible con LGPL.

Eso es solo lo que puedo pensar en mi cabeza, aunque tampoco soy un gran usuario de ninguno de los dos. También parece que podrías evitar JNA si querías una interfaz mejor que la que proporcionan, pero podrías codificarla en java.


  1. JNA no admite el mapeo de las clases de C ++, por lo que si está utilizando la biblioteca de C ++ necesitará un contenedor jni
  2. Si necesita mucha memoria para copiar. Por ejemplo, llama a un método que le devuelve un búfer de bytes grandes, cambia algo en él, luego necesita llamar a otro método que utiliza este búfer de bytes. Esto requeriría copiar este búfer de c a java, luego copiarlo 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 hay más. Pero, en general, el rendimiento no es tan diferente entre jna y jni, así que donde sea que puedas usar JNA, úsalo.

EDITAR

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

  1. Si necesita asignar 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:
    • Interoperabilidad dinámica C / C ++ / COM: llamar a métodos C ++, crear objetos C ++ (y clases de subclases C ++ desde Java!)
    • Mapeos de tipo directo con buen uso de genéricos (incluido un modelo mucho mejor para los 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 se puede evitar la copia de memoria.

Por lo tanto, sigo creyendo 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 alcanzado es notable.


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


De hecho, hice algunos benchmarks simples con JNI y JNA.

Como otros ya lo señalaron, JNA es por conveniencia. No necesita compilar o escribir código nativo cuando usa JNA. El cargador de bibliotecas nativo de JNA también es uno de los mejores / más fáciles de usar que he visto en mi vida. Lamentablemente, no se puede usar para JNI, parece. (Es por eso que escribí una alternativa para System.loadLibrary () que utiliza la convención de ruta de JNA y admite la carga sin fisuras desde el classpath (es decir, jar).

Sin embargo, el rendimiento de JNA puede ser mucho peor que el de JNI. Hice una prueba muy simple que llamó a una simple función de incremento entero nativo "return arg + 1;". Los puntos de referencia hechos 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 una matriz entera de 4 valores aún mostraba que el rendimiento de JNI es 3 veces más rápido que JNA. La ventaja reducida probablemente se debió a la forma en que accede a las matrices en JNI: mi ejemplo creó algunas cosas y las liberó nuevamente durante cada operación de suma.

El código y los resultados de la prueba se pueden encontrar en github .


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 tipo se implementa en el lado nativo del borde Java / native, mientras que con JNA, la conversión de tipo 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, supongo que JNI no parecerá demasiado complejo. Si usted es un programador de Java y solo necesita invocar una biblioteca nativa de un tercero, usar JNA es probablemente la ruta más fácil para evitar los problemas quizás no tan obvios con JNI.

Aunque nunca comparé las diferencias, lo haría por el diseño, al menos supongo que la conversión de tipo con JNA en algunas situaciones funcionará peor que con JNI. Por ejemplo, al pasar matrices, JNA las convertirá de Java a nativo al comienzo de cada llamada de función y volverá al final de la llamada de función. Con JNI, puede controlarse a sí mismo cuando se genera una "vista" nativa de la matriz, creando solo una vista de una parte de la matriz, manteniendo la vista a través de varias llamadas a funciones y al final liberar la vista y decidir si desea para mantener los cambios (posiblemente requiriendo copiar los datos) o descartar los cambios (no se requiere copia). Sé que puede usar una matriz nativa en llamadas a funciones con JNA utilizando la clase de memoria, pero esto también requerirá una copia de memoria, que puede ser innecesaria 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.


Investigué JNI y JNA para comparar el 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 JNI tiene un mayor rendimiento que JNA (aproximadamente 40 veces). Tal vez hay un truco para un mejor rendimiento en JNA, pero es muy lento para un simple ejemplo.


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 pensar que es una biblioteca bastante decente.

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


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


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

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

JANET luego traduce la Java incrustada en las llamadas JNI apropiadas.