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.