OutOfMemoryError: Przekroczono limit narzutów GC

1. Przegląd

Mówiąc najprościej, JVM dba o zwolnienie pamięci, gdy obiekty nie są już używane; ten proces nazywa się Garbage Collection (GC).

GC Głowica Przekroczenie limitu błędu jest jednym z rodziny java.lang.OutOfMemoryError i wskazania zasobu (pamięć), wyczerpania.

W tym krótkim artykule przyjrzymy się, co powoduje błąd java.lang.OutOfMemoryError: GC Overhead Limit Exceeded i jak można go rozwiązać.

2. Błąd przekroczenia limitu kosztów ogólnych GC

OutOfMemoryError jest podklasą klasy java.lang.VirtualMachineError ; jest generowany przez maszynę JVM, gdy napotka problem związany z wykorzystaniem zasobów. Mówiąc dokładniej, błąd występuje, gdy maszyna JVM spędzała zbyt dużo czasu na usuwaniu elementów bezużytecznych i była w stanie odzyskać tylko bardzo mało miejsca na sterty.

Zgodnie z dokumentacją Java, JVM jest domyślnie skonfigurowany do zgłaszania tego błędu, jeśli proces Java spędza ponad 98% czasu na wykonywaniu GC i gdy tylko mniej niż 2% sterty jest odzyskiwane w każdym przebiegu. Innymi słowy, oznacza to, że nasza aplikacja wyczerpała prawie całą dostępną pamięć, a moduł wyrzucania elementów bezużytecznych spędził zbyt dużo czasu na próbach jej wyczyszczenia i wielokrotnie zawodził.

W tej sytuacji użytkownicy doświadczają ekstremalnie powolnego działania aplikacji. Niektóre operacje, które zwykle kończą się w milisekundach, wymagają więcej czasu. Dzieje się tak, ponieważ procesor wykorzystuje całą swoją pojemność na czyszczenie pamięci i dlatego nie może wykonywać żadnych innych zadań.

3. Błąd w działaniu

Spójrzmy na fragment kodu, który generuje java.lang.OutOfMemoryError: Przekroczono limit kosztów GC.

Możemy to osiągnąć, na przykład, dodając pary klucz-wartość w niezakończonej pętli:

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

Gdy ta metoda jest wywoływana, z argumentami JVM jako -Xmx100m -XX: + UseParallelGC ( rozmiar sterty Java jest ustawiony na 100 MB, a algorytm GC to ParallelGC), otrzymujemy błąd java.lang.OutOfMemoryError: GC Overhead Limit Exceeded error. Aby lepiej zrozumieć różne algorytmy usuwania pamięci, możemy zapoznać się z samouczkiem Oracle Java Garbage Collection Basics.

Bardzo szybko otrzymamy java.lang.OutOfMemoryError: GC Overhead Limit Exceeded błąd, uruchamiając następujące polecenie z katalogu głównego projektu:

mvn exec:exec

Należy również zauważyć, że w niektórych sytuacjach możemy napotkać błąd przestrzeni sterty przed napotkaniem błędu Przekroczono limit narzutu GC .

4. Rozwiązywanie błędu przekroczenia limitu narzutu GC

Idealnym rozwiązaniem jest znalezienie podstawowego problemu z aplikacją poprzez zbadanie kodu pod kątem wycieków pamięci.

Należy odpowiedzieć na następujące pytania:

  • Jakie obiekty w aplikacji zajmują duże części sterty?
  • W jakich częściach kodu źródłowego są przydzielane te obiekty?

Możemy również skorzystać z automatycznych narzędzi graficznych, takich jak JConsole, które pomagają wykryć problemy z wydajnością w kodzie, w tym java.lang.OutOfMemoryErrors.

Ostatnim rozwiązaniem byłoby zwiększenie wielkości sterty poprzez zmianę konfiguracji uruchamiania maszyny JVM. Na przykład daje to 1 GB miejsca na sterty dla aplikacji Java:

java -Xmx1024m com.xyz.TheClassName

Nie rozwiąże to jednak problemu, jeśli w rzeczywistym kodzie aplikacji występują wycieki pamięci. Zamiast tego po prostu odłożymy błąd. Dlatego bardziej wskazane jest, aby ponownie dokładnie ocenić użycie pamięci przez aplikację.

5. Wniosek

W tym samouczku zbadaliśmy błąd java.lang.OutOfMemoryError: GC Overhead Limit Exceeded i jego przyczyny.

Jak zawsze, kod źródłowy związany z tym artykułem można znaleźć na GitHub.