Вопрос-ответ

Error java.lang.OutOfMemoryError: GC overhead limit exceeded

Ошибка java.lang.OutOfMemoryError: превышен лимит накладных расходов GC

Я получаю это сообщение об ошибке при выполнении своих JUnit тестов:

java.lang.OutOfMemoryError: GC overhead limit exceeded

Я знаю, что такое OutOfMemoryError, но что означает ограничение накладных расходов GC? Как я могу это решить?

Переведено автоматически
Ответ 1

Это сообщение означает, что по какой-то причине сборщик мусора отнимает чрезмерное количество времени (по умолчанию 98% всего процессорного времени процесса) и восстанавливает очень мало памяти при каждом запуске (по умолчанию 2% кучи).

Фактически это означает, что ваша программа перестает выполнять какой-либо прогресс и все время занята только сборкой мусора.

Чтобы ваше приложение не тратило процессорное время без выполнения каких-либо действий, JVM выдает это Error чтобы у вас был шанс диагностировать проблему.

Редкие случаи, когда я видел, как это происходило, заключались в том, что какой-то код создавал тонны временных объектов и тонны объектов со слабыми ссылками в среде, и без того сильно ограниченной памятью.

Ознакомьтесь с руководством по настройке Java GC, которое доступно для различных версий Java и содержит разделы, посвященные этой конкретной проблеме:

Ответ 2

Цитата из статьи Oracle "Настройка сборки мусора виртуальной машины Java SE 6 HotSpot [tm]":


Чрезмерное время сбора мусора и OutOfMemoryError


Параллельный сборщик выдаст OutOfMemoryError, если на сборку мусора тратится слишком много времени: если на сборку мусора потрачено более 98% общего времени и восстановлено менее 2% кучи, будет выдан OutOfMemoryError. Эта функция предназначена для предотвращения запуска приложений в течение длительного периода времени при незначительном прогрессе или вообще без него, поскольку куча слишком мала. При необходимости эту функцию можно отключить, добавив опцию -XX:-UseGCOverheadLimit в командную строку.


РЕДАКТИРОВАТЬ: похоже, кто-то может печатать быстрее меня :)

Ответ 3

Если вы уверены, что в вашей программе нет утечек памяти, попробуйте:


  1. Увеличьте размер кучи, например -Xmx1g.

  2. Включите сборщик с одновременной низкой паузой -XX:+UseConcMarkSweepGC.

  3. По возможности повторно используйте существующие объекты для экономии памяти.

При необходимости проверку лимита можно отключить, добавив опцию -XX:-UseGCOverheadLimit в командную строку.

Ответ 4

Обычно это код. Вот простой пример:

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

Использование Java 1.6.0_24-b07 в 32-разрядной версии Windows 7.

java -Xloggc:gc.log GarbageCollector

Затем посмотрите на gc.log


  • Срабатывало 444 раза с использованием НЕПРАВИЛЬНОГО метода

  • Срабатывало 666 раз с использованием ХУДШЕГО метода

  • Срабатывало 354 раза с использованием ЛУЧШЕГО метода

Теперь понятно, что это не лучший тест или не лучший дизайн, но когда вы сталкиваетесь с ситуацией, когда у вас нет выбора, кроме реализации такого цикла, или когда вы имеете дело с существующим кодом, который ведет себя плохо, выбор повторного использования объектов вместо создания новых может уменьшить количество раз, когда сборщик мусора мешает...

java