JNA semble un peu plus facile à utiliser pour appeler du code natif que JNI. Dans quels cas utiliseriez-vous JNI sur JNA?
Ce sont les problèmes que j'ai rencontrés. Il y a peut-être plus. Mais en général, les performances ne sont pas si différentes entre jna et jni, donc partout où vous pouvez utiliser JNA, utilisez-le.
[~ # ~] modifier [~ # ~]
Cette réponse semble être assez populaire. Voici donc quelques ajouts:
Donc, je pense toujours que dans la mesure du possible, il est préférable d'utiliser JNA ou BridJ, et de revenir à jni si les performances sont critiques, car si vous devez appeler fréquemment des fonctions natives, les performances sont perceptibles.
Il est difficile de répondre à une question aussi générique. Je suppose que la différence la plus évidente est qu'avec JNI, la conversion de type est implémentée du côté natif de la frontière Java/native, tandis qu'avec JNA, la conversion de type est implémentée en Java. Si vous vous sentez déjà assez à l'aise avec la programmation en C et devez implémenter vous-même du code natif, je suppose que JNI ne semble pas trop complexe. Si vous êtes un programmeur Java et que vous avez seulement besoin d'invoquer une bibliothèque native tierce, utiliser JNA est probablement le chemin le plus simple pour éviter les problèmes peut-être moins évidents avec JNI.
Bien que je n'ai jamais comparé de différences, je le ferais à cause de la conception, au moins supposons que la conversion de type avec JNA dans certaines situations fonctionnera moins bien qu'avec JNI. Par exemple, lors du passage de tableaux, JNA les convertit de Java en natif au début de chaque appel de fonction et de retour à la fin de l'appel de fonction. Avec JNI, vous pouvez contrôler vous-même quand un natif une "vue" du tableau est générée, ne créant potentiellement qu'une vue d'une partie du tableau, conservez la vue sur plusieurs appels de fonction et, à la fin, libérez la vue et décidez si vous souhaitez conserver les modifications (nécessitant éventuellement de copier le données) ou ignorer les modifications (aucune copie requise). Je sais que vous pouvez utiliser un tableau natif entre les appels de fonction avec JNA en utilisant la classe Memory, mais cela nécessitera également une copie de la mémoire, ce qui peut être inutile avec JNI. La différence peut ne pas être pertinent, mais si votre objectif initial est d'augmenter les performances des applications en implémentant certaines parties en code natif, l'utilisation d'une technologie de pont moins performante ne semble pas être le choix le plus évident.
C'est seulement ce que je peux trouver du haut de ma tête, bien que je ne sois pas un gros utilisateur non plus. Il semble également que vous pourriez éviter JNA si vous vouliez une meilleure interface que celle qu'ils fournissent, mais vous pouvez coder cela en Java.
Soit dit en passant, dans l'un de nos projets, nous avons conservé une très petite empreinte JNI. Nous avons utilisé des tampons de protocole pour représenter nos objets de domaine et n'avions donc qu'une seule fonction native pour relier Java et C (alors bien sûr, cette fonction C appelait un tas d'autres fonctions).
Ce n'est pas une réponse directe et je n'ai aucune expérience avec JNA mais, quand je regarde le Projets utilisant JNA et que je vois des noms comme SVNKit, IntelliJ IDEA, NetBeans IDE, etc., j'ai tendance à croire que c'est une bibliothèque assez décente.
En fait, je pense vraiment que j'aurais utilisé JNA au lieu de JNI quand je devais le faire car il semble en effet plus simple que JNI (qui a un processus de développement ennuyeux). Dommage, la JNA n'a pas été libérée à ce moment-là.
J'ai en fait fait quelques benchmarks simples avec JNI et JNA.
Comme d'autres l'ont déjà souligné, la JNA est pour plus de commodité. Vous n'avez pas besoin de compiler ou d'écrire du code natif lorsque vous utilisez JNA. Le chargeur de bibliothèque natif de JNA est également l'un des meilleurs/des plus faciles à utiliser que j'ai jamais vu. Malheureusement, vous ne pouvez pas l'utiliser pour JNI, semble-t-il. (C'est pourquoi j'ai écrit ne alternative pour System.loadLibrary () qui utilise la convention de chemin d'accès de JNA et prend en charge le chargement transparent à partir du chemin de classe (c'est-à-dire les jars).)
Cependant, les performances de JNA peuvent être bien pires que celles de JNI. J'ai fait un test très simple qui a appelé une fonction d'incrémentation d'entier natif simple "return arg + 1;". Les benchmarks effectués avec jmh ont montré que les appels JNI à cette fonction sont 15 fois plus rapides que JNA.
Un exemple plus "complexe" où la fonction native résume un tableau entier de 4 valeurs montre toujours que les performances JNI sont 3 fois plus rapides que JNA. L'avantage réduit était probablement dû à la façon dont vous accédez aux tableaux dans JNI: mon exemple a créé des éléments et les a à nouveau libérés lors de chaque opération de sommation.
Le code et les résultats des tests peuvent être trouvés sur github .
Si vous souhaitez des performances JNI mais que vous êtes intimidé par sa complexité, vous pouvez envisager d'utiliser des outils qui génèrent automatiquement des liaisons JNI. Par exemple, JANET (avertissement: je l'ai écrit) vous permet de mélanger Java et le code C++ dans un seul fichier source , et par exemple passer des appels de C++ à Java en utilisant la syntaxe standard Java. Par exemple, voici comment imprimer une chaîne C dans le Java:
native "C++" void printHello() {
const char* helloWorld = "Hello, World!";
`System.out.println(#$(helloWorld));`
}
JANET traduit ensuite le backtick-embedded Java en appels JNI appropriés.
J'ai étudié JNI et JNA pour la comparaison des performances parce que nous devions décider l'un d'entre eux d'appeler une DLL dans le projet et nous avions une contrainte de temps réel. Les résultats ont montré que JNI a des performances supérieures à JNA (environ 40 fois). Il existe peut-être une astuce pour de meilleures performances dans JNA, mais elle est très lente pour un exemple simple.
À moins que je manque quelque chose, la principale différence entre JNA et JNI n'est-elle pas qu'avec JNA, vous ne pouvez pas appeler le code Java à partir du code natif (C)?