Java/fr: Difference between revisions

From Alliance Doc
Jump to navigation Jump to search
(Created page with "== Pièges ==")
No edit summary
 
(29 intermediate revisions by 3 users not shown)
Line 1: Line 1:
<languages />
<languages />
Java est un langage de programmation de haut niveau orienté objet créé en 1995 par Sun Microsystems (rachetée en 2009 par Oracle). L'objectif central de Java est que les logiciels écrits dans ce langage obéissent au principe ''write once, run anywhere'' et sont très facilement portables sur plusieurs systèmes d’exploitation par le fait que le code source Java se compile en code octal (''bytecode'') pouvant être exécuté sur un environnement Java (JVM pour''Java virtual machine''); différentes architectures et plateformes peuvent donc constituer un environnement uniforme. Cette caractéristique fait de Java un langage populaire dans certains contextes et notamment pour l'apprentissage de la programmation. Même si l'accent n'est pas sur la performance, il existe des moyens d'augmenter la vitesse d'exécution et le langage a connu une certaine popularité auprès des scientifiques dans des domaines comme les sciences de la vie, d'où sont issus par exemple les outils d'analyse génomique [https://software.broadinstitute.org/gatk/ GATK] du Broad Institute. Le but de cette page n'est pas d'enseigner le langage Java, mais de fournir des conseils et suggestions pour son utilisation dans l'environnement CHP de Calcul Canada.  
[[Category:Software]]
Java est un langage de programmation de haut niveau orienté objet créé en 1995 par Sun Microsystems (rachetée en 2009 par Oracle). L'objectif central de Java est que les logiciels écrits dans ce langage obéissent au principe ''write once, run anywhere'' et sont très facilement portables sur plusieurs systèmes d’exploitation par le fait que le code source Java se compile en code octal (''bytecode'') pouvant être exécuté sur un environnement Java (JVM pour ''Java virtual machine''); différentes architectures et plateformes peuvent donc constituer un environnement uniforme. Cette caractéristique fait de Java un langage populaire dans certains contextes et notamment pour l'apprentissage de la programmation. Même si l'accent n'est pas sur la performance, il existe des moyens d'augmenter la vitesse d'exécution et le langage a connu une certaine popularité auprès des scientifiques dans des domaines comme les sciences de la vie, d'où sont issus par exemple les outils d'analyse génomique [https://software.broadinstitute.org/gatk/ GATK] du Broad Institute. Le but de cette page n'est pas d'enseigner le langage Java, mais de fournir des conseils et suggestions pour son utilisation sur les grappes de l'Alliance.  


Calcul Canada met à la disposition des utilisateurs plusieurs environnements Java via la commande <tt>module</tt>. En principe, vous aurez un seul module Java chargé à la fois. Les principales commandes associées aux modules Java sont&nbsp;:
L'Alliance offre plusieurs environnements Java via la commande [[Utiliser_des_modules | module]]. En principe, vous aurez un seul module Java chargé à la fois. Les principales commandes associées aux modules Java sont&nbsp;:
* <tt>java</tt> pour lancer en environnement Java;
* <tt>java</tt> pour lancer un environnement Java;
* <tt>javac</tt> pour appeler le compilateur Java qui convertit un fichier source Java en bytecode.  
* <tt>javac</tt> pour appeler le compilateur Java qui convertit un fichier source Java en bytecode.  


Line 33: Line 34:
== Pièges ==
== Pièges ==


===Memory Issues===
===Mémoire ===  
Java uses an automatic system called ''garbage collection'' to identify variables which are out of scope and return the memory associated with them to the operating system which however doesn't stop many Java programs from requiring significant amounts of memory to run correctly. When a Java virtual machine is launched using the <tt>java</tt> command by default the initial and maximum heap size are set to 1/64 and 1/4 of the system's physical memory respectively. This amount, particularly the maximum heap size, may well be inadequate and leaves a substantial amount of physical memory unused. To correct this problem, you can tell the Java virtual machine the maximum amount of memory to use with the command line argument <tt>Xmx</tt>, for instance
Une instance Java s'attend à avoir accès à toute la mémoire physique d'un nœud alors que l'ordonnanceur ou un interpréteur pourrait imposer ses limites (souvent différentes) dépendant des spécifications du script de soumission ou des limites du nœud de connexion. Dans un environnement de ressources partagées, ces limites font en sorte que des ressources à capacité finie comme la mémoire et les cœurs CPU ne sont pas épuisées par une tâche au détriment d'une autre.
{{Command|java -Xmx8192m -jar file.jar}} 
tells the Java virtual machine that it can use up to 8192 MB (8 GB) of memory. You can set the initial heap size with the argument <tt>Xms</tt> and you can see all the command line options the JVM is going to run with by specifying the following flag <tt>-XX:+PrintCommandLineFlags</tt>.


Alternatively, you can use the <tt>_JAVA_OPTIONS</tt> environment variable to set the run-time options rather that passing them on the command line. This is especially convenient if you launch multiple Java calls, or call a Java program from another Java program. Here is an example how to do it:
Quand une instance Java est lancée, elle fixe la valeur de deux paramètres selon la quantité de mémoire physique plutôt que la quantité de mémoire disponible comme suit ː
{{Command|export _JAVA_OPTIONS{{=}}"-Xms256m -Xmx2g"}}
* taille initiale du monceau (''heap''), 1/64 de la mémoire physique
When your Java program is run, it will produce a diagnostic message like this one "Picked up _JAVA_OPTIONS", verifying that the options have been picked up.
* taille maximale du monceau (''heap''), 1/4 de la mémoire physique


Please remember that the Java virtual machine itself creates a memory usage overhead. We recommend specifying the memory limit for your job as 1-2GB more than your setting on the Java command line option -Xmx.
En présence d'une grande quantité de mémoire physique, cette valeur de 1/4 peut aisément dépasser les limites imposées par l'ordonnanceur ou par un interpréteur et Java peut s'arrêter et produire des messages comme
  Could not reserve enough space for object heap
  There is insufficient memory for the Java Runtime Environment to continue.


===Garbage Collection===
Ces deux paramètres peuvent toutefois être explicitement contrôlés par l'un ou l'autre des énoncés suivants ː
By default, the Java VM uses a parallel garbage collector (GC) and sets a number of GC threads equal to the number of CPU cores on a given node, whether a Java job is threaded or not. Each GC thread consumes memory. Moreover, the amount of memory each GC thread consumes is proportional to the amount of physical memory. Therefore, we highly recommend matching the number of GC threads to the number of CPU cores you requested from the scheduler in your job submission script, like so <tt>-XX:ParallelGCThreads=12</tt> for example. You can also use the serial garbage collector by specifying the following option <tt>-XX:+UseSerialGC</tt>, whether your job is parallel or not.
  java -Xms256m -Xmx4g -version
ou
  java -XX:InitialHeapSize=256m -XX:MaxHeapSize=4g -version


===The <tt>volatile</tt> Keyword===
Pour voir toutes les options en ligne de commande que l'instance exécutera, utilisez l'indicateur  <code>-XX:+PrintCommandLineFlags</code> comme suit :
This keyword has a sense very different from that which C/C++ programmers are accustomed to. In Java <tt>volatile</tt> when applied to a variable has the effect of ensuring that its value is always read from and written to main memory, which can help to ensure that modifications of this variable are made visible to other threads. That said, there are contexts in which the use of the <tt>volatile</tt> keyword are not sufficient to avoid race conditions and the <tt>synchronized</tt> keyword is required to ensure program consistency.
<pre>
$ java -Xms256m -Xmx4g -XX:+PrintCommandLineFlags -version
-XX:InitialHeapSize=268435456 -XX:MaxHeapSize=4294967296 -XX:ParallelGCThreads=4 -XX:+PrintCommandLineFlags -XX:+UseCompressedOops -XX:+UseParallelGC
</pre>


==Further Reading==
Vous pouvez utiliser la variable d'environnement <tt>JAVA_TOOL_OPTIONS</tt> pour configurer les options d'exécution plutôt que de les spécifier en ligne de commande. Ceci s'avère utile quand des appels multiples sont lancés ou qu'un programme est appelé par un autre programme Java. Voici un exemple :
Scott Oaks and Henry Wong, ''Java Threads: Understanding and Mastering Concurrent Programming'' (3rd edition) (O'Reilly, 2012)
{{Commande|export JAVA_TOOL_OPTIONS{{=}}"-Xms256m -Xmx2g"}}
 
 
À l'exécution, le programme émet un message de diagnostic semblable à ''Picked up JAVA_TOOL_OPTIONS''; ceci indique que les options ont été prises en compte.
 
N'oubliez pas que l'instance Java crée elle-même une réserve d'utilisation de la mémoire. Nous recommandons que la limite par tâche soit fixée à 1 ou 2Go de plus que la valeur de l'option <tt>-Xmx</tt>.
 
===Garbage Collection (GC)===
Java utilise le processus automatique de ''Garbage Collection'' pour identifier les variables avec des valeurs non valides et retourner la mémoire qui leur est associée au système d'exploitation. Par défaut, l'instance Java utilise un GC parallèle et détermine un nombre de fils GC égal au nombre de cœurs CPU du nœud, que la tâche Java soit ou non multifil. Chacun des fils GC consomme de la mémoire. De plus, la quantité de mémoire consommée par les fils GC est proportionnelle à la quantité de mémoire physique. Nous vous recommandons donc fortement d'avoir un nombre de fils GC égal au nombre de cœurs CPU que vous demandez à l'ordonnanceur dans le script de soumission avec par exemple <tt>-XX:ParallelGCThreads=12</tt>. Vous pouvez aussi utiliser le GC séquentiel avec l'option <tt>-XX:+UseSerialGC</tt>, que la tâche soit ou non parallèle.
 
===Mot-clé <tt>volatile</tt> ===  
Le sens de ce mot-clé est très différent de celui du même terme utilisé en programmation C/C++. La valeur d'une variable Java ayant cet attribut est toujours lue directement de la mémoire principale et toujours écrite directement dans la mémoire principale; toute modification à la variable sera donc visible par tous les autres fils. Dans certains contextes cependant, <tt>volatile</tt> ne suffit pas à empêcher les situations de compétition (''race conditions'') et <tt>synchronized</tt> est nécessaire pour maintenir la cohérence du programme.
 
==Références==
OAKS, Scott et Henry Wong, Java Threads: Understanding and Mastering Concurrent Programming, 3e édition, O'Reilly, 2012.

Latest revision as of 19:38, 17 April 2023

Other languages:

Java est un langage de programmation de haut niveau orienté objet créé en 1995 par Sun Microsystems (rachetée en 2009 par Oracle). L'objectif central de Java est que les logiciels écrits dans ce langage obéissent au principe write once, run anywhere et sont très facilement portables sur plusieurs systèmes d’exploitation par le fait que le code source Java se compile en code octal (bytecode) pouvant être exécuté sur un environnement Java (JVM pour Java virtual machine); différentes architectures et plateformes peuvent donc constituer un environnement uniforme. Cette caractéristique fait de Java un langage populaire dans certains contextes et notamment pour l'apprentissage de la programmation. Même si l'accent n'est pas sur la performance, il existe des moyens d'augmenter la vitesse d'exécution et le langage a connu une certaine popularité auprès des scientifiques dans des domaines comme les sciences de la vie, d'où sont issus par exemple les outils d'analyse génomique GATK du Broad Institute. Le but de cette page n'est pas d'enseigner le langage Java, mais de fournir des conseils et suggestions pour son utilisation sur les grappes de l'Alliance.

L'Alliance offre plusieurs environnements Java via la commande module. En principe, vous aurez un seul module Java chargé à la fois. Les principales commandes associées aux modules Java sont :

  • java pour lancer un environnement Java;
  • javac pour appeler le compilateur Java qui convertit un fichier source Java en bytecode.

Les logiciels Java sont fréquemment distribués sous forme de fichiers JAR portant le suffixe jar. Pour utiliser un logiciel Java, utilisez la commande

Question.png
[nom@serveur ~]$ java -jar file.jar

Parallélisme

Fils d'exécution

Java permet la programmation avec fils, éliminant ainsi le recours à des interfaces et librairies comme OpenMP, pthreads et Boost qui sont nécessaires avec d'autres langages. L'objet Java principal pour traiter la concurrence est la classe Thread; on peut l'employer en fournissant une méthode Runnable à la classe Thread standard ou encore en définissant la classe Thread comme sous-classe, comme démontré ici :

Fichier : thread.java

public class HelloWorld extends Thread {
        public void run() {
            System.out.println("Hello World!");
        }
        public static void main(String args[]) {
            (new HelloWorld()).start();
        }
}


Cette approche est généralement la plus simple, mais présente cependant le désavantage de ne pas permettre l'héritage multiple; la classe qui implémente l'exécution concurrente ne peut donc pas avoir en sous-classe une autre classe potentiellement plus utile.

MPI

On utilise souvent la librairie MPJ Express pour obtenir un parallélisme de type MPI.

Pièges

Mémoire

Une instance Java s'attend à avoir accès à toute la mémoire physique d'un nœud alors que l'ordonnanceur ou un interpréteur pourrait imposer ses limites (souvent différentes) dépendant des spécifications du script de soumission ou des limites du nœud de connexion. Dans un environnement de ressources partagées, ces limites font en sorte que des ressources à capacité finie comme la mémoire et les cœurs CPU ne sont pas épuisées par une tâche au détriment d'une autre.

Quand une instance Java est lancée, elle fixe la valeur de deux paramètres selon la quantité de mémoire physique plutôt que la quantité de mémoire disponible comme suit ː

  • taille initiale du monceau (heap), 1/64 de la mémoire physique
  • taille maximale du monceau (heap), 1/4 de la mémoire physique

En présence d'une grande quantité de mémoire physique, cette valeur de 1/4 peut aisément dépasser les limites imposées par l'ordonnanceur ou par un interpréteur et Java peut s'arrêter et produire des messages comme

 Could not reserve enough space for object heap
 There is insufficient memory for the Java Runtime Environment to continue.

Ces deux paramètres peuvent toutefois être explicitement contrôlés par l'un ou l'autre des énoncés suivants ː

 java -Xms256m -Xmx4g -version

ou

 java -XX:InitialHeapSize=256m -XX:MaxHeapSize=4g -version

Pour voir toutes les options en ligne de commande que l'instance exécutera, utilisez l'indicateur -XX:+PrintCommandLineFlags comme suit :

$ java -Xms256m -Xmx4g -XX:+PrintCommandLineFlags -version
-XX:InitialHeapSize=268435456 -XX:MaxHeapSize=4294967296 -XX:ParallelGCThreads=4 -XX:+PrintCommandLineFlags -XX:+UseCompressedOops -XX:+UseParallelGC

Vous pouvez utiliser la variable d'environnement JAVA_TOOL_OPTIONS pour configurer les options d'exécution plutôt que de les spécifier en ligne de commande. Ceci s'avère utile quand des appels multiples sont lancés ou qu'un programme est appelé par un autre programme Java. Voici un exemple :

Question.png
[nom@serveur ~]$ export JAVA_TOOL_OPTIONS="-Xms256m -Xmx2g"


À l'exécution, le programme émet un message de diagnostic semblable à Picked up JAVA_TOOL_OPTIONS; ceci indique que les options ont été prises en compte.

N'oubliez pas que l'instance Java crée elle-même une réserve d'utilisation de la mémoire. Nous recommandons que la limite par tâche soit fixée à 1 ou 2Go de plus que la valeur de l'option -Xmx.

Garbage Collection (GC)

Java utilise le processus automatique de Garbage Collection pour identifier les variables avec des valeurs non valides et retourner la mémoire qui leur est associée au système d'exploitation. Par défaut, l'instance Java utilise un GC parallèle et détermine un nombre de fils GC égal au nombre de cœurs CPU du nœud, que la tâche Java soit ou non multifil. Chacun des fils GC consomme de la mémoire. De plus, la quantité de mémoire consommée par les fils GC est proportionnelle à la quantité de mémoire physique. Nous vous recommandons donc fortement d'avoir un nombre de fils GC égal au nombre de cœurs CPU que vous demandez à l'ordonnanceur dans le script de soumission avec par exemple -XX:ParallelGCThreads=12. Vous pouvez aussi utiliser le GC séquentiel avec l'option -XX:+UseSerialGC, que la tâche soit ou non parallèle.

Mot-clé volatile

Le sens de ce mot-clé est très différent de celui du même terme utilisé en programmation C/C++. La valeur d'une variable Java ayant cet attribut est toujours lue directement de la mémoire principale et toujours écrite directement dans la mémoire principale; toute modification à la variable sera donc visible par tous les autres fils. Dans certains contextes cependant, volatile ne suffit pas à empêcher les situations de compétition (race conditions) et synchronized est nécessaire pour maintenir la cohérence du programme.

Références

OAKS, Scott et Henry Wong, Java Threads: Understanding and Mastering Concurrent Programming, 3e édition, O'Reilly, 2012.