Accès rapide :
Utilisation de l'outil jlink
A quoi sert l'outil jlink
Aide en ligne de l'outil jlink
Création d'une image via l'outil jlink.
Démarrage d'une image.
Utilisation de l'outil jaotc
Qu'est-ce que l'« Ahead of Time Compilation »
Aide en ligne de l'outil jaotc
Compilation anticipée d'un code Java
Exécution d'une librairie produite par jaotc
JLink permet de produire une nouvelle « JVM light » dans laquelle vous allez stocker uniquement les codes des modules utilisés par votre programme : les modules non utilisés du Java SE ne seront pas injecté dans cette nouvelle JVM. Cet outil va fusionner l'ensemble des modules utilisés (modules standards Java SE, modules applicatifs et modules des librairies utilisées) en une seule archive qui permettra l'exécution de votre programme.
La nouvelle JVM produite sera appelée une image et elle sera auto-suffisante. Vous pourrez alors déployer cette image sur les postes clients sans nécessiter l'installation d'une JVM traditionnelle.
La première étape consiste à obtenir de l'aide en ligne sur l'outil. Pour ce faire vous pouvez lancer cet outil avec l'option --help
.
Voici le résultat produit.
$> jlink --help Usage: jlink <options> --module-path <modulepath> --add-modules <module>[,<module>...] Possible options include: --add-modules <mod>[,<mod>...] Root modules to resolve in addition to the initial modules. <mod> can also be ALL-MODULE-PATH. --bind-services Link in service provider modules and their dependences -c, --compress=<0|1|2> Enable compression of resources: Level 0: No compression Level 1: Constant string sharing Level 2: ZIP --disable-plugin <pluginname> Disable the plugin mentioned --endian <little|big> Byte order of generated jimage (default:native) -h, --help, -? Print this help message --ignore-signing-information Suppress a fatal error when signed modular JARs are linked in the image. The signature related files of the signed modular JARs are not copied to the runtime image. --launcher <name>=<module>[/<mainclass>] Add a launcher command of the given name for the module and the main class if specified --limit-modules <mod>[,<mod>...] Limit the universe of observable modules --list-plugins List available plugins -p, --module-path <path> Module path. If not specified, the JDKs jmods directory will be used, if it exists. If specified, but it does not contain the java.base module, the JDKs jmods directory will be added, if it exists. --no-header-files Exclude include header files --no-man-pages Exclude man pages --output <path> Location of output path --post-process-path <imagefile> Post process an existing image --resources-last-sorter <name> The last plugin allowed to sort resources --save-opts <filename> Save jlink options in the given file -G, --strip-debug Strip debug information --suggest-providers [<name>,...] Suggest providers that implement the given service types from the module path -v, --verbose Enable verbose tracing --version Version information @<filename> Read options from file $>
Donc, pour créer une image de votre application, vous devez utiliser l'outil jlink
.
Vous devez lui spécifier le(s) dossier(s) contenant les modules à importer dans l'image (paramètre --module-path
),
l'ensemble des modules à importer (paramètre --add-modules
) et le nom de l'image à produire (paramètre --output
).
java.base
).
Il n'est donc pas nécessaire de les spécifier.
$> jlink --module-path . --add-modules fr.koor.myapp --output image
image
correspond au nom de l'image produite. Vous auriez pu aussi utiliser le nom de votre application comme nom d'image.
Dans ce cas, la JVM associée à l'image pourra être démarrée en lançant le programme image/bin/java
.
Le problème est que dans ce cas, il faudra spécifier un certain nombre de paramètres lors du démarrage de la JVM : notamment le nom de la classe de
démarrage.
Mais il est aussi possible de générer un autre exécutable permettant de démarrer directement le programme sur votre classe de démarrage
(celle qui porte la méthode main
).
$> jlink --module-path . --add-modules fr.koor.myapp --output image --launcher start=fr.koor.myapp/fr.koor.myapp.Start
image/bin/start
(ce qui correspond à l'information localisée en partie gauche du paramètre
--launcher
). Le premier fr.koor.myapp
du launcher correspond au nom du module portant la classe de démarrage.
Le second correspond au package (dans le module initialement spécifié) contenant la classe de démarrage (ici Start
).
Deux possibilités vous sont proposées pour démarrer votre image. Soit en procédant à un démarrage traditionnel d'une JVM, soit en utilisant
l'exécutable personnalisé produit par jlink (grâce à l'option --launcher
).
Pour démarrer la JVM de manière traditionnelle, vous devez spécifier l'option -m
pour spécifier le module contenant la classe de démarrage
et le nom de cette classe. Voici un exemple.
$> image/bin/java -m fr.koor.myapp/fr.koor.myapp.Start
Si vous utilisez l'exécutable personnalisé, les choses sont bien plus simples : vous n'avez plus besoin de spécifier de paramètre, comme le montre l'exemple suivant.
$> image/bin/start
Historiquement parlant, Java utilise un « JIT Compiler » (Just In Time Compiler). Effectivement, l'outil javac
(le compilateur Java) produit du code en langage machine pour le processeur virtuel Java. Le problème, c'est que personne ne possède un tel processeur
(il est virtuel). Du coup, la JVM finalise la phase de compilation durant son exécution : cela à un petit impacte sur les performances de la JVM.
L'intérêt de cette approche réside dans le fait que vous livrez un programme qui peut, potentiellement, s'exécuter sur n'importe quelle architecture.
Il y a néanmoins des cas, ou l'utilisation d'un JIT Compiler pose problème : c'est notamment le cas avec les systèmes iOS, ou cette technologie est prohibée par les contrats de licence. Une autre situation ou le JIT n'est pas préconisé, c'est pour tout ce qui est système embarqué (voir mobile). Effectivement, ces systèmes fonctionnent souvent avec des batteries et finaliser la construction du programme au runtime a pour effet de consommer plus de batterie. Dans de tels cas, vous pouvez utiliser l'AOT.
Un compilateur AOT (Ahead Of Time Compiler) réalise, en quelque sorte, l'opposé d'un JIT Compiler. La traduction du code machine Java est effectuée une fois pour toute à la construction du programme et avant la première exécution de ce dernier.
Un avantage de l'AOT est qu'on a plus une vision d'ensemble sur le code à compiler. En conséquence les optimisations produites sur le code machine sont souvent bien meilleures qu'avec un compilateur JIT.
Depuis, la version 9.0 du Java SE, un compilateur AOT expérimental est proposé dans le JDK (en Java SE 14, il est toujours proposé comme étant une
fonctionnalité expérimentale). Il se nomme jaotc
et il est localisé dans le répertoire bin
de votre JDK.
Vous trouverez ci-dessous l'aide en ligne proposée par l'outil jaotc
.
$> jaotc --help Usage: jaotc <options> list list A : separated list of class names, modules, jar files or directories which contain class files. where options include: --output <file> Output file name --class-name <class names> List of classes to compile --jar <jarfiles> List of jar files to compile --module <modules> List of modules to compile --directory <dirs> List of directories where to search for files to compile --search-path <dirs> List of directories where to search for specified files --compile-commands <file> Name of file with compile commands --compile-for-tiered Generate profiling code for tiered compilation --compile-with-assertions Compile with java assertions --compile-threads <number> Number of compilation threads to be used --ignore-errors Ignores all exceptions thrown during class loading --exit-on-error Exit on compilation errors --info Print information during compilation --verbose Print verbose information --debug Print debug information -? -h --help Print this help message --version Version information --linker-path Full path to linker executable -J<flag> Pass <flag> directly to the runtime system $>
Vous pouvez compiler, pour la plateforme considérée, des simples fichiers .class
avec jaotc
.
$> jaotc --output ../libSimpleSample.so -J-cp -J./bin SimpleSample
.class
localisé dans le répertoire bin-J
),
mais c'est la seule manière qui marche pour le moment.
lib
et doit se terminer par le suffixe .so
(Shared Object). D'où le nom proposé pour la librairie de code natif : libSimpleSample.so
.
Si vous êtes sur système Windows, une telle librairie doit se terminer par le suffixe .dll
(Dynamic Linking Library).
Dans ce cas, le nom de la librairie devra être SimpleSample.dll
.
Vous pouvez aussi compiler des modules Java (qu'ils soient aux formats Jar ou JMod). Voici des exemples de lancement de la compilation sur des modules Java (prédéfinis ou non).
$> jaotc --output ../libjava.base.so --module java.base
$> jaotc --output ../libsuperlib.so fr.koor.superlib.jar
Pour exécuter un code compilé en AOT, vous devez utiliser l'option -XX:AOTLibrary
.
Imaginons le programme suivant.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public class SimpleSample { public static String doSomething() { System.out.println( "In doSomething" ); return "ok"; } public static void main(String[] args) { System.out.println( "Hello - " + Math.random() ); System.out.println( doSomething() ); } } |
Voici un exemple de compilation AOT et de démarrage d'une JVM à partir de la librairie produite.
$> jaotc --output ../libSimpleSample.so -J-cp -J./bin SimpleSample $> java -XX:+UnlockExperimentalVMOptions -XX:AOTLibrary=./libSimpleSample.so SimpleSample Hello - 0.9272779396108479 In doSomething ok $>
-XX:+UnlockExperimentalVMOptions
.
Améliorations / Corrections
Vous avez des améliorations (ou des corrections) à proposer pour ce document : je vous remerçie par avance de m'en faire part, cela m'aide à améliorer le site.
Emplacement :
Description des améliorations :