Fout java.lang.OutOfMemoryError: GC overhead limiet overschreden

Ik krijg deze foutmelding als ik mijn JUnit tests uitvoer:

java.lang.OutOfMemoryError: GC overhead limit exceeded

Ik weet wat een OutOfMemoryError is, maar wat betekent GC overhead limit? Hoe kan ik dit oplossen?

Oplossing

Deze melding betekent dat de vuilnisman om de een of andere reden buitensporig veel tijd nodig heeft (standaard 98% van alle CPU-tijd van het proces) en maar heel weinig geheugen terugwint in elke run (standaard 2% van de heap).

Dit betekent in feite dat je programma geen voortgang meer boekt en de hele tijd alleen nog maar bezig is met de vuilnisverzameling.

Om te voorkomen dat je programma CPU tijd opslokt zonder iets gedaan te krijgen, gooit de JVM deze Error, zodat je een kans hebt om het probleem te diagnosticeren.

De zeldzame gevallen waarin ik dit heb zien gebeuren is waar sommige code tonnen tijdelijke objecten en tonnen objecten met zwakke referenties aan het maken was in een al zeer geheugen beperkte omgeving.

Kijk naar dit artikel voor details (specifiek dit deel).

Commentaren (14)

De GC gooit deze exceptie wanneer te veel tijd wordt besteed aan garbage collection voor te weinig opbrengst, bv. 98% van CPU tijd wordt besteed aan GC en minder dan 2% van de heap wordt teruggewonnen.

Deze eigenschap is ontworpen om te voorkomen dat toepassingen gedurende een lange periode draaien terwijl ze weinig of geen vooruitgang boeken omdat de heap te klein is.

U kunt dit uitzetten met de commandoregeloptie -XX:-UseGCOverheadLimit

Meer info hier

EDIT: het lijkt erop dat iemand sneller kan typen dan ik :)

Commentaren (6)

Het'is meestal de code. Hier's een eenvoudig voorbeeld:

import java.util.*;

public class GarbageCollector {

    public static void main(String... args) {

        System.out.printf("Testing...%n");
        List list = new ArrayList();
        for (int outer = 0; outer < 10000; outer++) {

            // list = new ArrayList(10000); // BAD
            // list = new ArrayList(); // 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");
    }
}

Met java 1.6.0_24-b07 op een Windows7 32 bit.

java -Xloggc:gc.log GarbageCollector

Kijk dan naar gc.log

  • 444 keer getriggerd met BAD-methode
  • 666 keer geactiveerd met de slechtere methode
  • 354 keer geactiveerd met de BETERE methode

Toegegeven, dit is niet de beste test of het beste ontwerp, maar als je geconfronteerd wordt met een situatie waarin je geen andere keuze hebt dan zo'n lus te implementeren of als je te maken hebt met bestaande code die zich slecht gedraagt, kan de keuze om objecten te hergebruiken in plaats van nieuwe te maken het aantal keren dat de vuilnisman in de weg loopt verminderen...

Commentaren (1)