Je reçois ce message d'erreur lorsque j'exécute mes tests JUnit :
java.lang.OutOfMemoryError: GC overhead limit exceeded
Je sais ce qu'est une OutOfMemoryError
, mais que signifie la limite d'overhead GC ? Comment puis-je résoudre ce problème ?
Ce message signifie que, pour une raison quelconque, le ramasseur de déchets prend un temps excessif (par défaut 98% du temps CPU du processus) et récupère très peu de mémoire à chaque exécution (par défaut 2% du tas).
Cela signifie que votre programme ne progresse plus et qu'il ne s'occupe que du ramasse-miettes à tout moment.
Pour éviter que votre application n'accapare le temps CPU sans rien faire, la JVM lance cette Error
pour que vous ayez une chance de diagnostiquer le problème.
Les rares cas où j'ai vu cela se produire sont ceux où un code créait des tonnes d'objets temporaires et des tonnes d'objets faiblement référencés dans un environnement déjà très limité en mémoire.
Consultez [cet article][1] pour plus de détails (en particulier [cette partie][2]).
[1] : http://www.oracle.com/technetwork/java/javase/gc-tuning-6-140523.html [2] : http://www.oracle.com/technetwork/java/javase/gc-tuning-6-140523.html#par_gc.oom
La GC lève cette exception lorsque trop de temps est consacré à la collecte des déchets pour un rendement trop faible, par exemple lorsque 98 % du temps du CPU est consacré à la GC et que moins de 2 % du tas est récupéré.
Cette fonctionnalité est conçue pour empêcher les applications de fonctionner pendant une période prolongée tout en faisant peu ou pas de progrès parce que le tas est trop petit.
Vous pouvez désactiver cette fonction avec l'option de la ligne de commande `-XX:-UseGCOverheadLimit'.
Plus d'informations [ici] (http://java.sun.com/javase/technologies/hotspot/gc/gc_tuning_6.html#par_gc.oom)
EDIT : on dirait que quelqu'un tape plus vite que moi :)
C'est généralement le code. Voici un exemple simple :
import java.util.*;
public class GarbageCollector {
public static void main(String... args) {
System.out.printf("Testing...%n");
List<Double> list = new ArrayList<Double>();
for (int outer = 0; outer < 10000; outer++) {
// list = new ArrayList<Double>(10000); // BAD
// list = new ArrayList<Double>(); // WORSE
list.clear(); // BETTER
for (int inner = 0; inner < 10000; inner++) {
list.add(Math.random());
}
if (outer % 1000 == 0) {
System.out.printf("Outer loop at %d%n", outer);
}
}
System.out.printf("Done.%n");
}
}
Utilisation de java 1.6.0_24-b07 sur un Windows7 32 bits.
java -Xloggc:gc.log GarbageCollector
Regardez ensuite le fichier gc.log
Certes, il ne s'agit pas du meilleur test ou de la meilleure conception, mais lorsque vous êtes confronté à une situation où vous n'avez pas d'autre choix que d'implémenter une telle boucle ou lorsque vous avez affaire à du code existant qui se comporte mal, choisir de réutiliser des objets au lieu d'en créer de nouveaux peut réduire le nombre de fois où le ramasseur de déchets se met en travers de votre chemin...