Перейти к основному содержимому

OutOfMemoryError: Превышен лимит накладных расходов сборщика мусора

· 3 мин. чтения

1. Обзор

Проще говоря, JVM заботится об освобождении памяти, когда объекты больше не используются. Этот процесс называется сборкой мусора ( GC ).

Ошибка GC Overhead Limit Exceeded относится к семейству java.lang.OutOfMemoryError и указывает на исчерпание ресурса (памяти).

В этом кратком руководстве мы рассмотрим, что вызывает ошибку java.lang.OutOfMemoryError: GC Overhead Limit Exceeded и как ее можно устранить.

2. Ошибка превышения лимита служебных данных GC

OutOfMemoryError является подклассом java.lang.VirtualMachineError . Он вызывается JVM, когда сталкивается с проблемой, связанной с использованием ресурсов. В частности, ошибка возникает, когда JVM тратит слишком много времени на сборку мусора и может освободить очень мало места в куче.

Согласно документам Java, по умолчанию JVM настроена на выдачу этой ошибки, если процесс Java тратит более 98% своего времени на сборку мусора и когда при каждом запуске восстанавливается менее 2% кучи. Другими словами, это означает, что наше приложение исчерпало почти всю доступную память, а сборщик мусора потратил слишком много времени на ее очистку и несколько раз терпел неудачу.

В этой ситуации пользователи испытывают крайнюю медлительность приложения. Некоторые операции, которые обычно выполняются за миллисекунды, занимают больше времени. Это связано с тем, что ЦП использует всю свою мощность для сборки мусора и, следовательно, не может выполнять какие-либо другие задачи.

3. Ошибка в действии

Давайте посмотрим на фрагмент кода, который выдает ошибку java.lang.OutOfMemoryError: GC Overhead Limit Exceeded .

Мы можем добиться этого, например, добавив пары ключ-значение в незавершенный цикл:

public class OutOfMemoryGCLimitExceed {
public static void addRandomDataToMap() {
Map<Integer, String> dataMap = new HashMap<>();
Random r = new Random();
while (true) {
dataMap.put(r.nextInt(), String.valueOf(r.nextInt()));
}
}
}

При вызове этого метода с аргументами JVM в виде -Xmx100m -XX:+UseParallelGC (размер кучи Java установлен равным 100 МБ, а алгоритм GC — ParallelGC) мы получаем ошибку java.lang.OutOfMemoryError: GC Overhead Limit Exceeded . Чтобы лучше понять различные алгоритмы сборки мусора, ознакомьтесь с учебным пособием Oracle по основам сборки мусора Java .

Мы очень быстро получим ошибку java.lang.OutOfMemoryError: GC Overhead Limit Exceeded , выполнив следующую команду из корня проекта :

mvn exec:exec

Следует также отметить, что в некоторых ситуациях мы можем столкнуться с ошибкой пространства в куче до появления ошибки GC Overhead Limit Exceeded .

4. Устранение ошибки превышения лимита служебных данных GC

Идеальное решение — найти основную проблему с приложением, изучив код на наличие утечек памяти.

Эти вопросы необходимо решить:

  • Какие объекты в приложении занимают большую часть кучи?
  • В каких частях исходного кода размещаются эти объекты?

Мы также можем использовать автоматизированные графические инструменты, такие как JConsole , которые помогают обнаруживать проблемы с производительностью в коде, включая java.lang.OutOfMemoryErrors .

В крайнем случае можно увеличить размер кучи, изменив конфигурацию запуска JVM.

Например, это дает 1 ГБ пространства кучи для приложения Java:

java -Xmx1024m com.xyz.TheClassName

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

5. Вывод

В этой статье мы рассмотрели ошибку java.lang.OutOfMemoryError: GC Overhead Limit Exceeded и ее причины.

Как всегда, исходный код, относящийся к этой статье, можно найти на GitHub .