Грешка java.lang.OutOfMemoryError: GC overhead limit exceeded

Получавам това съобщение за грешка, когато изпълнявам тестовете на JUnit:

java.lang.OutOfMemoryError: GC overhead limit exceeded

Знам какво е OutOfMemoryError, но какво означава GC overhead limit? Как мога да реша този проблем?

Решение

Това съобщение означава, че по някаква причина колекторът за отпадъци отнема прекалено много време (по подразбиране 98% от цялото процесорно време на процеса) и възстановява много малко памет при всяко изпълнение (по подразбиране 2% от купчината).

Това на практика означава, че програмата ви спира да извършва какъвто и да е прогрес и е заета да изпълнява само събирането на боклука през цялото време.

За да предотврати поглъщането на процесорното време на вашето приложение, без да свърши нищо, JVM изхвърля тази Error, за да имате възможност да диагностицирате проблема.

Редките случаи, в които съм виждал това да се случва, са, когато някой код създаваше тонове временни обекти и тонове слабо реферирани обекти в и без това много ограничена откъм памет среда.

Вижте тази статия за подробности (по-специално тази част).

Коментари (14)

GC хвърля това изключение, когато се изразходва твърде много време за събиране на отпадъци срещу твърде малка възвръщаемост, например 98% от процесорното време се изразходва за GC, а се възстановяват по-малко от 2% от купчината.

Тази функция е създадена, за да предотврати продължителна работа на приложенията, които не постигат никакъв или почти никакъв напредък, тъй като купчината е твърде малка.

Можете да я изключите с опцията от командния ред -XX:-UseGCOverheadLimit

Повече информация тук

EDIT: изглежда, че някой може да пише по-бързо от мен :)

Коментари (6)

Обикновено това е кодът. Ето един прост пример:

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");
    }
}

Използвам java 1.6.0_24-b07 на Windows7 32 bit.

java -Xloggc:gc.log GarbageCollector

След това погледнете gc.log

  • Задействан 444 пъти чрез метода BAD
  • задействан 666 пъти при използване на лош метод
  • задействан 354 пъти при използване на ПО-ДОБЪР метод

Сега, разбира се, това не е най-добрият тест или най-добрият дизайн, но когато сте изправени пред ситуация, в която нямате друг избор, освен да приложите такъв цикъл, или когато се занимавате със съществуващ код, който се държи зле, изборът на повторно използване на обектите, вместо създаването на нови, може да намали броя на случаите, в които колекторът за боклук застава на пътя...

Коментари (1)