Learn · concepts

Qu'est-ce que le JNI ? Interface Native Java pour les moddeurs

L'interface native Java (JNI) est le pont intégré de Java pour appeler du code C/C++ depuis la JVM et inversement. C'est la méthode standard utilisée par un mod Minecraft pour charger une bibliothèque native.

TRtrolPublished 6 min read

Qu'est-ce que JNI en termes simples ?

L'interface native Java (JNI) est la partie de Java qui relie deux mondes : le bytecode géré sur la JVM et le code machine compilé écrit en C ou en C++. Une méthode reçoit le mot-clé native et n'a pas de corps, et au moment de l'exécution, la JVM l'associe à une fonction correspondante dans une bibliothèque native chargée. À partir de là, les deux côtés échangent des arguments et des valeurs de retour.

La frontière n'est pas unidirectionnelle. La fonction native reçoit un pointeur JNIEnv, et cette poignée est la passerelle de retour vers Java : elle expose des appels pour lire et écrire des champs Java, invoquer des méthodes Java, construire des objets et lever des exceptions. Ainsi, le même pont qui permet à Java d'appeler vers l'extérieur permet également à C d'appeler vers l'intérieur.

Pourquoi un mod ou un client Minecraft toucherait-il au code natif ?

La plupart des programmes Java n'ont jamais besoin de JNI. Un mod y a recours lorsque la JVM seule ne peut pas faire le travail, généralement pour les graphiques, l'audio, l'intégration du système d'exploitation ou une routine qui doit être rapide. La bibliothèque native effectue le travail lourd et JNI est la méthode standard pour la charger et l'appeler.

Réutiliser une bibliothèque C éprouvée

Une base de code native et mature résout déjà le problème. Le réécrire en Java serait une perte de temps, c'est pourquoi le module s'y lie plutôt.

Atteindre le système d'exploitation

Certaines fonctionnalités de la plateforme n'ont pas d'API Java pure. Un appel natif devient alors le seul moyen d'y accéder.

Une voie brûlante

Une routine numérique étroite ou de bas niveau peut s'exécuter plus rapidement en tant que code natif compilé qu'en tant que bytecode sur la JVM.

Piloter les matériels et les pilotes

Le rendu, l'audio et l'accès aux périphériques se trouvent souvent derrière les bibliothèques natives que JNI expose au code Java.

Comment fonctionne un appel JNI de bout en bout ?

Le flux est identique sur toutes les plateformes : déclarez la méthode en Java, compilez une fonction C correspondante en une bibliothèque partagée, chargez-la au moment de l'exécution, laissez la JVM les lier par nom, puis appelez à travers. Les noms de fonction suivent un schéma fixe afin que la JVM puisse les résoudre, et un fichier d'en-tête généré précise la signature exacte à implémenter.

ÉtapeCe qui se passe
DéclarationUne méthode Java est écrite avec le mot-clé native et laissée vide du côté Java.
ConstructionUne fonction C ou C++ est compilée en une bibliothèque partagée : .dll sur Windows, .so sur Linux, .dylib sur macOS.
ChargementJava appelle System.loadLibrary pour charger cette bibliothèque pendant l'exécution du programme.
LiaisonLa JVM associe chaque méthode native à sa fonction C par une signature déformée par le nom.
AppelJava invoque la méthode ; le contrôle passe au code natif et revient avec un résultat.

Quel est le coût de JNI pour vous ?

JNI est puissant, mais il a des arêtes vives. Le code natif s’exécutant en dehors du filet de sécurité de la JVM, une erreur entraîne l’arrêt de l’ensemble du processus plutôt que de déclencher une exception capturable. La mémoire allouée du côté natif est invisible pour le ramasse-miettes, de sorte que les fuites s’accumulent à moins qu’elles ne soient libérées manuellement. Chaque passage entraîne une surcharge, ce qui rend coûteux l’appel à travers la limite dans une boucle serrée. Et les constructions natives sont verrouillées à une plateforme : une DLL Windows ne se chargera pas sous Linux sans une compilation séparée.

Ce que ça procure

  • Accès direct aux bibliothèques C et C++ existantes
  • Un moyen d'accéder aux fonctionnalités du système d'exploitation et du matériel que la JVM ne peut atteindre
  • Exécution à la vitesse native pour les routines les plus utilisées

Ce que ça coûte

  • Un crash natif peut faire tomber toute la JVM
  • Gestion manuelle de la mémoire sans filet de sécurité du ramasse-miettes
  • Builds spécifiques à chaque plateforme à maintenir et à distribuer
  • Surcharge inter-domaines dans les boucles critiques

JNI face à l'API des fonctions et de la mémoire étrangères

JNI est le mécanisme original, mais il n'est plus le seul. Les versions récentes de Java incluent l'API des fonctions et de la mémoire étrangères (FFM), conçue pour appeler le code natif avec moins de code répétitif et des garanties de sécurité plus strictes. JNI domine toujours les chaînes d'outils existantes car il est omniprésent et parfaitement compris.

JNIAPI FFM
ÂgeOriginal, présent depuis les débuts de JavaModerne, ajoutée dans les versions récentes
Code répétitifEn-têtes générés, fonctions C à noms modifiésHandles de méthodes définis en Java, pas de code C intermédiaire
Sécurité de la mémoireManuelle ; les erreurs peuvent corrompre la JVMSegments limités avec des vérifications plus robustes
AdoptionOmniprésente dans les bibliothèques existantesEn croissance, dans les nouvelles bases de code

FAQ

Obtenez Terminus

Built by people who actually read the JVM internals.