OutOfMemoryError: Превишен лимит на режима на GC

1. Общ преглед

Просто казано, JVM се грижи за освобождаването на паметта, когато обектите вече не се използват; този процес се нарича Събиране на боклук (GC).

В надземната Надвишен лимит GC Грешката е един от семейството на java.lang.OutOfMemoryError и е индикация за ресурс (памет) изтощение.

В тази кратка статия ще разгледаме какво причинява грешката java.lang.OutOfMemoryError: GC Overhead Limit Превишена и как тя може да бъде решена.

2. Превишена грешка в GC Overhead Limit

OutOfMemoryError е подклас на java.lang.VirtualMachineError ; изхвърля се от JVM, когато срещне проблем, свързан с използването на ресурси. По-конкретно, грешката възниква, когато JVM е прекарал твърде много време в събиране на боклука и е успял да възстанови само много малко място за купчина.

Според Java docs, по подразбиране JVM е конфигуриран да изхвърля тази грешка, ако Java процесът прекарва повече от 98% от времето си в GC и когато при всяко изпълнение се възстановяват само по-малко от 2% от купчината. С други думи, това означава, че нашето приложение е изчерпало почти цялата налична памет и Събирачът на боклук е прекарал твърде много време, опитвайки се да го почисти и не е успял многократно.

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

3. Грешка в действие

Нека да разгледаме част от кода, която хвърля java.lang.OutOfMemoryError: Превишена е горната граница на GC.

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

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

Когато този метод се извика, с аргументите на JVM като -Xmx100m -XX: + UseParallelGC ( размерът на купчината Java е зададен на 100MB и алгоритъмът на GC е ParallelGC), получаваме java.lang.OutOfMemoryError: GC Overhead Limit Exceeded error. За да получите по-добро разбиране на различните алгоритми за събиране на боклук, можем да проверим урока по Основи на Java за събиране на боклук на Oracle.

Ще получим java.lang.OutOfMemoryError: GC Overhead Limit Превишена грешка много бързо, като изпълним следната команда от корена на проекта:

mvn exec:exec

Трябва също да се отбележи, че в някои ситуации може да срещнем грешка в пространството на купчина, преди да срещнем грешката на GC Overhead Limed Exceeded .

4. Преодоляване на превишена грешка в GC Overhead Limit

Идеалното решение е да се намери основният проблем с приложението, като се изследва кодът за всички течове на памет.

Трябва да бъдат разгледани следните въпроси:

  • Какви са обектите в приложението, които заемат големи части от купчината?
  • В кои части на изходния код се разпределят тези обекти?

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

Крайната мярка би била да се увеличи размерът на купчината чрез промяна на конфигурацията за стартиране на JVM. Например, това дава 1GB място за купчина за приложението Java:

java -Xmx1024m com.xyz.TheClassName

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

5. Заключение

В този урок разгледахме java.lang.OutOfMemoryError: GC Overhead Limit Превишена и причините за това.

Както винаги, изходният код, свързан с тази статия, може да бъде намерен в GitHub.