java.lang.OutOfMemoryError: Miejsce na sterty Java

97

Podczas wykonywania programu wielowątkowego pojawia się następujący błąd

java.lang.OutOfMemoryError: Java heap space

Powyższy błąd wystąpił w jednym z wątków.

  1. O ile mi wiadomo, przestrzeń sterty jest zajmowana tylko przez zmienne instancji. Jeśli to prawda, to dlaczego ten błąd wystąpił po pewnym czasie działania poprawnie, ponieważ na przykład zmienne są przydzielane w momencie tworzenia obiektu.

  2. Czy istnieje sposób na zwiększenie miejsca na sterty?

  3. Jakie zmiany należy wprowadzić w moim programie, aby zajmował mniej miejsca na stercie?

Yatendra Goel
źródło

Odpowiedzi:

105

Jeśli chcesz zwiększyć swoją przestrzeń sterty, możesz użyć java -Xms<initial heap size> -Xmx<maximum heap size>w wierszu poleceń. Domyślnie wartości są oparte na wersji środowiska JRE i konfiguracji systemu. Więcej informacji na temat opcji maszyn wirtualnych można znaleźć w witrynie Java .

Zalecałbym jednak profilowanie aplikacji, aby dowiedzieć się, dlaczego zjadany jest rozmiar twojej sterty. NetBeans zawiera bardzo dobry program do profilowania . Uważam, że wykorzystuje jvisualvmpod maską. Dzięki profilerowi możesz spróbować dowiedzieć się, gdzie jest tworzonych wiele obiektów, kiedy obiekty są zbierane jako elementy bezużyteczne i nie tylko.

Thomas Owens
źródło
1
Używam Netbeans, ale nie wiem, jak używać profilera. Chciałbym dowiedzieć się więcej na temat programu profilującego, aby móc go używać do wykrywania wycieków pamięci w mojej aplikacji.
Yatendra Goel
Dodałem odsyłacz do strony w serwisie NetBeans ( profiler.netbeans.org ), która zawiera bardzo dobrą dokumentację dotyczącą profilu, od podstaw do bardziej zaawansowanych zastosowań.
Thomas Owens
Wartości domyślne zmieniają się wraz z wersjami Java, dobrze byłoby uwzględnić te informacje w swojej odpowiedzi.
Dariusz
Po prostu naprawiłem podobny problem i najpierw spróbowałem: java -jar Division.jar -Xmx512m -Xms512m - to daje ten sam błąd, ale kiedy robię to w ten sposób: java -Xmx512m -Xms512m -jar Division.jar - wszystko jest w porządku. Dlatego kolejność parametrów jest również ważna.
hipokito
@hipokito Argumenty po przekazaniu pliku jar do metody main () pliku jar jako argumenty []
Asu
29

1. - Tak, ale odnosi się do całej pamięci używanej przez twój program.

2. - Tak, zobacz opcje Java VM

-Xms<size>        set initial Java heap size
-Xmx<size>        set maximum Java heap size

To znaczy

java -Xmx2g przypisz maksymalnie 2 gigabajty pamięci RAM do swojej aplikacji

Ale powinieneś najpierw sprawdzić, czy nie masz wycieku pamięci.

3.- To zależy od programu. Spróbuj wykryć wycieki pamięci. Trudno odpowiedzieć na to pytanie. Ostatnio możesz profilować za pomocą JConsole, aby spróbować dowiedzieć się, dokąd zmierza twoja pamięć

OscarRyz
źródło
podczas gdy (prawda);)
Gal Bracha
8

Możesz zajrzeć na tę stronę, aby dowiedzieć się więcej o pamięci w JVM: http://developer.streamezzo.com/content/learn/articles/optimization-heap-memory-usage

Zauważyłem, że przydatne jest użycie visualgc do obserwowania, jak różne części modelu pamięci zapełniają się, aby określić, co zmienić.

Trudno jest określić, która część pamięci została zapełniona, stąd visualgc, ponieważ możesz chcieć po prostu zmienić część, w której występuje problem, zamiast po prostu powiedzieć,

W porządku! Dam 1G pamięci RAM do JVM.

Postaraj się być bardziej precyzyjny w tym, co robisz, na dłuższą metę prawdopodobnie okaże się, że program jest do tego lepszy.

Aby określić, gdzie może być wyciek pamięci, możesz użyć do tego testów jednostkowych, sprawdzając, jaka była pamięć przed testem i po nim, a jeśli zmiana jest zbyt duża, możesz chcieć ją zbadać, ale musisz sprawdź, czy test jest jeszcze uruchomiony.

James Black
źródło
6

Aby zwiększyć wielkość sterty, można użyć argumentu -Xmx podczas uruchamiania języka Java; na przykład

-Xmx256M
Adamskiego
źródło
6

Możesz uzyskać rozmiar pamięci sterty za pomocą poniższego programu.

public class GetHeapSize {
    public static void main(String[] args) {
        long heapsize = Runtime.getRuntime().totalMemory();
        System.out.println("heapsize is :: " + heapsize);
    }
} 

możesz odpowiednio zwiększyć rozmiar sterty również za pomocą: java -Xmx2g http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html

user2663609
źródło
6
  1. O ile mi wiadomo, przestrzeń sterty jest zajmowana tylko przez zmienne instancji. Jeśli to prawda, to dlaczego ten błąd wystąpił po pewnym czasie działania poprawnie, ponieważ na przykład zmienne są przydzielane w momencie tworzenia obiektu.

Oznacza to, że tworzysz więcej obiektów w swojej aplikacji przez pewien okres czasu w sposób ciągły. Nowe obiekty będą przechowywane w pamięci sterty i to jest powodem wzrostu pamięci sterty.

Sterta zawiera nie tylko zmienne instancji. Będzie przechowywać wszystkie inne niż pierwotne typy danych (obiekty). Czas życia tych obiektów może być krótki (blok metody) lub długi (do momentu odniesienia do obiektu w aplikacji)

  1. Czy istnieje sposób na zwiększenie miejsca na sterty?

Tak. Spójrz na ten artykuł wyroczniWięcej informacji .

Istnieją dwa parametry do ustawiania rozmiaru sterty:

-Xms:, który ustawia początkowy i minimalny rozmiar sterty

-Xmx:, który ustawia maksymalny rozmiar sterty

  1. Jakie zmiany należy wprowadzić w moim programie, aby zajmował mniej miejsca na stercie?

To zależy od twojej aplikacji.

  1. Ustaw maksymalną pamięć sterty zgodnie z wymaganiami aplikacji

  2. Nie powoduj wycieków pamięci w swojej aplikacji

  3. Jeśli zauważysz wycieki pamięci w swojej aplikacji, znajdź główną przyczynę za pomocą narzędzi do profilowania, takich jak MAT , Visual VM , jconsole itp. Po znalezieniu głównej przyczyny usuń wycieki.

Ważne uwagi z artykułu oracle

Przyczyna: Komunikat szczegółowy dotyczący przestrzeni sterty Java wskazuje, że nie można przydzielić obiektu w stercie Java. Ten błąd niekoniecznie oznacza wyciek pamięci.

Możliwe przyczyny:

  1. Nieprawidłowa konfiguracja (nie przydzielanie wystarczającej pamięci)
  2. Aplikacja nieumyślnie przechowuje odniesienia do obiektów, co zapobiega gromadzeniu elementów bezużytecznych
  3. Aplikacje, które nadmiernie wykorzystują finalizatory. Jeśli klasa ma metodę finalize, to obiekty tego typu nie mają odzyskiwanej przestrzeni w czasie czyszczenia pamięci. Jeśli wątek finalizatora nie może nadążyć za kolejką finalizacji, wówczas sterta Java mogłaby się zapełnić i zostałby zgłoszony wyjątek OutOfMemoryError tego typu .

Z innej strony, użyj lepszych algorytmów zbierania śmieci ( CMS lub G1GC )

Spójrz na to pytanie, aby zrozumieć G1GC

Ravindra babu
źródło
5
  1. W większości przypadków kod nie jest zoptymalizowany. Wypuść te przedmioty, które Twoim zdaniem nie będą już potrzebne. Unikaj tworzenia obiektów w pętli za każdym razem. Spróbuj użyć pamięci podręcznych. Nie wiem, jak radzi sobie Twoja aplikacja. Ale w programowaniu obowiązuje również jedna zasada normalnego życia

    Lepiej jest zapobiegać niż leczyć. „Nie twórz niepotrzebnych obiektów”

DKSRathore
źródło
3
  1. Zmienne lokalne znajdują się na stosie. Miejsce na stercie jest zajęte przez obiekty.

  2. Możesz skorzystać z -Xmxopcji.

  3. Zasadniczo miejsce na sterty jest zużywane za każdym razem, gdy przydzielasz nowy obiekt newi zwalniasz jakiś czas po tym, jak obiekt nie jest już przywoływany. Dlatego upewnij się, że nie zachowujesz odniesień do obiektów, których już nie potrzebujesz.

sepp2k
źródło
1

Nie, myślę, że myślisz o miejscu na stosie. Miejsce na stercie jest zajęte przez obiekty. Sposobem na zwiększenie jest -Xmx256m, zastępując 256 ilością potrzebną w wierszu poleceń.

Yishai
źródło
1

Aby uniknąć tego wyjątku, jeśli używasz JUnit i Spring, spróbuj dodać to w każdej klasie testowej:

@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
Aliuk
źródło
0

W netbeans przejdź do paska narzędzi „Uruchom”, -> „Ustaw konfigurację projektu” -> „Dostosuj” -> „uruchom” wyskakującego okna -> „Opcja maszyny wirtualnej” -> wypełnij „-Xms2048m” -Xmx2048m ”. To może rozwiązać problem wielkości sterty.

Xiaogang
źródło