Pregunta

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

¿Fue útil?

Solución

  1. JNA no admite la asignación de clases de C ++, así que si estás usando C ++ biblioteca necesitará un envoltorio JNI
  2. Si necesita una gran cantidad de copias de la memoria. Por ejemplo, se llama a un método que devuelve un gran buffer de bytes, se cambia algo en él, entonces es necesario llamar a otro método que utiliza esta memoria intermedia de bytes. Para ello sería necesario que copie este buffer de C a Java, y luego copiar de nuevo de Java para c. En este caso JNI va a ganar en el rendimiento, ya que puede mantener y modificar este buffer 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 el JNA y JNI, por lo que siempre se puede utilizar JNA, utilizarlo.

Editar

Esta respuesta parece ser bastante popular. Así que aquí están algunas adiciones:

  1. Si necesita asignar C ++ o COM, hay una biblioteca por Oliver Chafic, creador de JNAerator, llamado BridJ . Todavía es una biblioteca joven, pero tiene muchas características interesantes:
    • Dynamic C / C ++ / interoperabilidad COM: (! Y la subclase C ++ clases de Java) llamar a los métodos C ++, cree objetos ++ C
    • asignaciones de tipo directa, con un buen uso de los genéricos (incluyendo modelo mucho más agradable para los punteros)
    • Soporte completo JNAerator
    • funciona en Windows, Linux, MacOS X, Solaris, Android
  2. En cuanto a la copia de la memoria, creo JNA apoya ByteBuffers directos, por lo que la copia de memoria se puede 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, ya que si es necesario llamar a las funciones nativas con frecuencia, impacto en el rendimiento es notable.

Otros consejos

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 lleva a cabo en el lado natural de la frontera Java / nativo, mientras que con JNA, la conversión de tipo es implementado en Java. Si ya sentirse muy a gusto con la programación en C y tienen que implementar algún código nativo mismo, yo supongo que JNI no parecer demasiado compleja. Si usted es un programador de Java y sólo necesita invocar una biblioteca nativa de terceros, utilizando JNA es probablemente el camino más fácil para evitar los problemas que tal vez no tan obvios con JNI.

A pesar de que nunca he Benchmarked cualquier diferencia, me debido al diseño, al menos suponer que la conversión de tipo con JNA en algunas situaciones se comportará peor que con la JNI. Por ejemplo, cuando pasar matrices, JNA convertirá éstos de Java para nativo al comienzo de cada llamada a la función y volver al final de la llamada de función. Con JNI, puede controlar a sí mismo cuando se genera una "vista" nativa de la matriz, lo que podría solamente la creación de una vista de una parte de la matriz, mantener la visión a través de varias llamadas a la función ya la liberación final de la vista y decide si desea para mantener los cambios (potencialmente requiere para copiar la parte trasera de datos) o descartar los cambios (no copia requerida). Sé que usted puede utilizar una matriz nativa a través de llamadas a funciones con JNA utilizando la clase de memoria, pero esto también va a requerir copia de memoria, que puede ser innecesario con JNI. La diferencia puede no ser relevante, pero si su objetivo original es aumentar el rendimiento de aplicaciones mediante la implementación de partes de ella en código nativo, utilizando una tecnología puente peor rendimiento no parece ser la opción más obvia.

  1. Usted está escribiendo código hace unos pocos años antes de que hubiera JNA o se dirigen a un pre 1.4 JRE.
  2. El código que está trabajando no está en una DLL \ SO.
  3. Usted está trabajando en código que es incompatible con la LGPL.

Esto es sólo lo que puede llegar a la parte superior de la cabeza, aunque no soy un gran consumidor de cualquiera. También parece que es posible evitar el JNA si quería una interfaz mejor que la que proporcionan pero se puede codificar en torno a que en Java.

Por cierto, en uno de nuestros proyectos, que mantenían una muy pequeña huella JNI. Hemos utilizado búferes de protocolo para la representación de los objetos de dominio y por lo tanto sólo tenía una función nativa para tender un puente de Java y C (entonces, por supuesto, que la función C llamaría un montón de otras funciones).

Si desea un rendimiento JNI pero está intimidado por su complejidad, es posible considerar el uso de herramientas que generan automáticamente los enlaces de JNI. Por ejemplo, JANET (disclaimer: Me lo escribió) le permite mezclar Java y C ++ código en una sola archivo de origen, y por ejemplo, hacer llamadas desde C ++ para Java usando la sintaxis de Java estándar. Por ejemplo, aquí te mostramos cómo imprimir 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 se traduce el Java backtick embebido en el JNI apropiada llama.

De hecho, me hice algunos puntos de referencia simples con JNI y JNA.

Como otros ya se ha señalado, JNA es por conveniencia. No es necesario para compilar o escribir código nativo cuando se utiliza JNA. cargador de biblioteca nativa de JNA es también uno de los mejores / más fácil de usar que he visto nunca. Lamentablemente, no se puede utilizar para JNI que parece. (Es por eso que escribí una alternativa para System.loadLibrary () que utiliza la convención de camino de la JNA y soporta carga sin problemas desde la ruta de clase (es decir, frascos).)

El rendimiento del JNA sin embargo, puede ser mucho peor que la de JNI. Hice una prueba muy simple que llama un simple número entero nativa función de incremento "retorno arg + 1;". Los puntos de referencia realizados con JMH mostraron que JNI llamadas a la función que son 15 veces más rápido que el JNA.

A ejemplo más "complejo" donde la función nativa resume una matriz de enteros de 4 valores todavía mostró que el rendimiento JNI es 3 veces más rápido que JNA. La ventaja reducida fue probablemente debido a cómo se accede a las matrices en JNI: mi ejemplo creado algunas cosas y lo soltó de nuevo durante cada operación sumando

.

Código y resultados de pruebas se pueden encontrar en github .

Me investigado JNI y JNA para la comparación de rendimiento porque teníamos que decidir uno de ellos para llamar a una DLL en el proyecto y tuvimos una restricción de tiempo real. Los resultados han demostrado que JNI tiene mayor rendimiento que JNA (aproximadamente 40 veces). Tal vez hay un truco para un mejor rendimiento en el JNA, pero es muy lento para un ejemplo sencillo.

A menos que me falta algo, no es la principal diferencia entre JNA vs JNI que con JNA no puede llamar a código Java de código nativo (C)?

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top