03 février 2010

Erreurs de débutant en Java: fermer les fichiers !

Les développeurs Java débutants (j'en vois qui ont de l'expérience et qui continuent de faire cette erreur chaque jour ...) considèrent souvent qu'il est inutile de libérer les ressources allouées.

Comme il s'agit de Java et que le Garbage Collector veille, il est trop souvent considéré que la mémoire se libère de façon automatique, ce qui n'est que partiellement vrai.

Une des erreurs courantes consiste à ne pas fermer les fichiers ouverts, que ce soit en lecture ou en écriture.

Considérons la méthode suivante qui consiste à copier un fichier par bloc de 1024 octets sur un autre filesystem:

public static boolean copyTo(File src, File dest, boolean close)
throws IOException {
FileOutputStream out = null;
FileInputStream in = null;
try {
if (!src.exists())
throw new FileNotFoundException(src.getAbsolutePath());
if (dest.exists() || !dest.createNewFile())
return false;
out = new FileOutputStream(dest);
in = new FileInputStream(src);
int len = 1024;
int nread;
byte[] b = new byte[len];
for (;;)
if ( (nread = in.read(b, 0, len)) <= 0) break; else out.write(b, 0, nread); return true; } finally { if (close) { try { out.close(); } catch (IOException ioe) { } try { in.close(); } catch (IOException ioe) { } } } }


Le paramètre close permet de fermer ou non les flux ouverts (input et output).

Si on appelle cette méthode, par exemple 2048 fois avec un nom de fichier de destination qui change et le paramètre close à false, on obtient l'erreur suivante:

java.io.IOException: Too many open files
at java.io.UnixFileSystem.createFileExclusively(Native Method)
at java.io.File.createNewFile(File.java:883)
at FileNotClosed.copyTo(FileNotClosed.java:36)
at FileNotClosed.main(FileNotClosed.java:17)


Et on n'arrive qu'à copier 510 fichiers, ce qui veux dire qu'on en a ouvert 2*510 soit 1020 fichiers, parce que le max open files défini par process sur cette machine Linux est de 1024:

ulimit -a
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 32768
max locked memory (kbytes, -l) 32
max memory size (kbytes, -m) unlimited
open files (-n) 1024
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 8192
cpu time (seconds, -t) unlimited
max user processes (-u) 32768
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited

Les autres fichiers ouverts le sont par la JVM elle même.

En conséquence de quoi, il est primordial de fermer TOUS les fichiers ouverts après leur utilisation, et ce de façon systématique dans le bloc finally afin que la fermeture soit faites dans tous les cas.

Evidemment si un System.exit() est appelé, le bloc finally correspondant lui ne le sera pas.

Ce genre d'erreur se voit tous les jours, et dans un serveur d'applications par exemple, cela fait des ravages !

Autres posts liés à Développement / Logiciel / Java / Shell / C:

Heure d'été, Classe Date, JDK 1.5 et TimeZone
Un très ancien bug non découvert jusque là
pop3/tcp server failing (looping), service terminated
De l’usage des programmes d’exemple
JavaMail en IMAP avec un serveur Exchange

Libellés : , , , , , , , , , , , , ,

1 commentaires:

Blogger PY a dit...

Appeler System.gc() dans le bloc finally de la méthode copyTo(...) aide à réduire le problème, parce que dans ce cas les méthodes protected void finalize() des classes FileInputStream et FileOutputStream sont appelées puisqu'on les forcent à l'être.

Néanmoins, cela ne constitue pas une solution, car l'appel au Garbage Collector est très coûteux.

9:32 PM  

Enregistrer un commentaire

Abonnement Publier les commentaires [Atom]

<< Accueil

16 décembre 2006

Sun annonce Java 6 (Java SE 6)

Sun Microsystems vient de sortir la version 6 de Java Plateform Standard Edition (Java SE 6).

Cette version 6 de Java, qui a mis deux ans à sortir des laboratoires de Sun, serait 30% plus performante que Java 5, et la nouvelle machine virtuelle de Sun mettrait moitié moins de temps à démarrer.

La nouvelle JVM (Java Virtual machine) de Sun s'adapte désormais à la plate-forme matérielle d'exécution, notamment aux caractéristiques du processeur.

Parmi les ajouts de Java 6, on peut citer l'interopérabilité avec les langages de scripts comme Javascript, PHP ou Ruby ainsi que le support des services Web, sans avoir besoin d'une plate-forme J2EE.

Par contre, il semble que Java 6 n'intègre pas pour l'instant le support du langage de script groovy.

Les développeurs et ingénieurs logiciels qui travaillent avec Java vont certainement faire des tests prochainement pour voir si les promesses de Sun Microsystems sont au rendez-vous.

Java 6 est disponible pour Solaris x86, Solaris x64, Windows ainsi que pour plusieurs distributions Linux (en format RPM pour Linux et Linux x64).

De plus, le code source du JDK SE 6 est disponible sur le site de Sun.

Enfin, le langage Java devrait être disponible en Open Source prochainement, d'après les dires de Sun.

Libellés : , , , , ,

1 commentaires:

Blogger Emmanuel Fougeras a dit...

Il y a également d'autres innovations sympathiques comme :
- l'amélioration des JTabbebPane
- l'ajout de la gestion du systray
- la possibilité de définir l'écran de chargement d'une application Swing
- une nouvelle API permettant de mieux exploiter les spécificités des différents bureaux

Bref, une belle mise à jour que ce Java 6

--
Emmanuel Fougeras
http://emmanuelfougeras.blogspot.com/

8:21 PM  

Enregistrer un commentaire

Abonnement Publier les commentaires [Atom]

<< Accueil