Piszę aplikację Swing po stronie klienta (graficzny projektant czcionek) na Javie 5 . Ostatnio java.lang.OutOfMemoryError: Java heap space
popełniam błąd, ponieważ nie jestem konserwatywny w kwestii użycia pamięci. Użytkownik może otworzyć nieograniczoną liczbę plików, a program przechowuje otwarte obiekty w pamięci. Po szybkich badaniach znalazłem ergonomię w wirtualnej maszynie Java 5.0 i innych, którzy mówili na maszynie Windows, że domyślna maksymalna wielkość sterty maszyny JVM to 64MB
.
W tej sytuacji, jak mam sobie poradzić z tym ograniczeniem?
Mógłbym zwiększyć maksymalny rozmiar sterty za pomocą opcji wiersza poleceń do java, ale wymagałoby to wykrycia dostępnej pamięci RAM i napisania programu uruchamiającego lub skryptu. Poza tym zwiększenie do pewnego skończonego maksimum ostatecznie nie pozbywa się problemu.
Mógłbym przepisać część mojego kodu, aby często utrwalać obiekty w systemie plików (korzystanie z bazy danych to samo) w celu zwolnienia pamięci. To może działać, ale prawdopodobnie też dużo pracy.
Jeśli mógłbyś wskazać mi szczegóły powyższych pomysłów lub niektóre alternatywy, takie jak automatyczna pamięć wirtualna, dynamiczne zwiększanie wielkości sterty , byłoby świetnie.
źródło
Odpowiedzi:
Ostatecznie zawsze masz skończoną maksymalną stertę, z której możesz korzystać bez względu na platformę, na której pracujesz. W 32-bitowym systemie Windows jest to około
2GB
(nie sterty, ale całkowita ilość pamięci na proces). Zdarza się, że Java decyduje się na zmniejszenie domyślnej wartości (prawdopodobnie po to, aby programiści nie mogli tworzyć programów, które mają przydział pamięci, nie wpadając w ten problem i nie musząc dokładnie zbadać, co robią).Biorąc to pod uwagę, istnieje kilka metod, które można zastosować, aby określić, jakiej ilości pamięci potrzebujesz lub zmniejszyć ilość używanej pamięci. Jednym z powszechnych błędów w przypadku śmieci, takich jak Java lub C #, jest przechowywanie odniesień do obiektów, których już nie używasz, lub przydzielanie wielu obiektów, gdy można zamiast tego użyć ich ponownie . Tak długo, jak obiekty mają do nich odniesienie, będą nadal korzystać z miejsca na sterty, ponieważ śmieciarz ich nie usunie.
W takim przypadku możesz użyć profilera pamięci Java, aby ustalić, które metody w twoim programie przydzielają dużą liczbę obiektów, a następnie ustalić, czy istnieje sposób, aby upewnić się, że nie są one już przywoływane, lub w ogóle ich nie przydzielać. Jedną z opcji, z których korzystałem w przeszłości, jest „JMP” http://www.khelekore.org/jmp/ .
Jeśli stwierdzisz, że alokujesz te obiekty z jakiegoś powodu i musisz trzymać się referencji (w zależności od tego, co robisz, może tak być), po prostu musisz zwiększyć maksymalny rozmiar sterty podczas uruchamiania programu. Jednak po wykonaniu profilowania pamięci i zrozumieniu, w jaki sposób przydzielane są twoje obiekty, powinieneś mieć lepszy pomysł na to, ile pamięci potrzebujesz.
Ogólnie rzecz biorąc, jeśli nie możesz zagwarantować, że twój program będzie działał w pewnej skończonej ilości pamięci (być może w zależności od wielkości wejściowej), zawsze napotkasz ten problem. Dopiero po wyczerpaniu tego wszystkiego będziesz musiał zajrzeć do buforowania obiektów na dysk itp. W tym momencie powinieneś mieć bardzo dobry powód, aby powiedzieć „Potrzebuję Xgb pamięci” do czegoś i nie możesz obejść tego, ulepszając algorytmy lub wzorce alokacji pamięci. Zasadniczo dzieje się tak zwykle tylko w przypadku algorytmów działających na dużych zestawach danych (takich jak baza danych lub jakiś program do analizy naukowej), a następnie techniki takie jak buforowanie i IO odwzorowywane w pamięci stają się przydatne.
źródło
Uruchom Javę z opcją wiersza polecenia
-Xmx
, która określa maksymalny rozmiar sterty.Zobacz tutaj, aby uzyskać szczegółowe informacje .
źródło
Możesz określić dla każdego projektu, ile miejsca na stosie chce twój projekt
Poniżej znajduje się dla Eclipse Helios / Juno / Kepler :
Kliknij prawym przyciskiem myszy
następnie dodaj to
źródło
Zwiększenie wielkości stosu nie jest „naprawą”, lecz „tynkiem”, w 100% tymczasowym. Zepsuje się w innym miejscu. Aby uniknąć tych problemów, napisz kod o wysokiej wydajności.
źródło
Duże zastrzeżenie - w moim biurze stwierdziliśmy, że (na niektórych komputerach z systemem Windows) nie możemy przeznaczyć więcej niż 512 m na stertę Java. Okazało się, że jest to spowodowane programem antywirusowym Kaspersky zainstalowanym na niektórych z tych komputerów. Po odinstalowaniu tego produktu AV, stwierdziliśmy, że możemy przydzielić co najmniej 1,6 GB, tj.
-Xmx1600m
(M jest obowiązkowe, w przeciwnym razie spowoduje kolejny błąd „Zbyt mała początkowa sterty”).Nie mam pojęcia, czy dzieje się tak w przypadku innych produktów AV, ale prawdopodobnie dzieje się tak, ponieważ program AV rezerwuje mały blok pamięci w każdej przestrzeni adresowej, zapobiegając w ten sposób pojedynczemu naprawdę dużemu przydziałowi.
źródło
Argumenty VM działały dla mnie w zaćmieniu. Jeśli używasz Eclipse w wersji 3.4, wykonaj następujące czynności
przejdź do,
Run --> Run Configurations -->
a następnie wybierz projekt w maven build -> następnie wybierz zakładkę „JRE” -> następnie naciśnij-Xmx1024m
.Możesz też
Run --> Run Configurations --> select the "JRE" tab -->
wpisać -Xmx1024m
Powinno to zwiększyć stos pamięci dla wszystkich kompilacji / projektów. Powyższy rozmiar pamięci wynosi 1 GB. Możesz zoptymalizować, jak chcesz.
źródło
Tak, dzięki
-Xmx
czemu możesz skonfigurować więcej pamięci dla JVM. Aby mieć pewność, że nie wyciekasz ani nie marnujesz pamięci. Zrób zrzut stosu i użyj Eclipse Memory Analyzer do analizy zużycia pamięci.źródło
Chciałbym dodać rekomendacje z artykułu dotyczącego rozwiązywania problemów z wyrocznią .
Wyjątek w wątku nazwa_wątku: java.lang.OutOfMemoryError: Przestrzeń sterty Java
Możliwe przyczyny:
Prosty problem z konfiguracją , gdy określony rozmiar sterty jest niewystarczający dla aplikacji.
Aplikacja mimowolnie przechowuje odwołania do obiektów , co zapobiega gromadzeniu śmieci.
Nadmierne użycie finalizatorów .
Po odśmiecaniu obiekty są kolejkowane w celu finalizacji , co nastąpi później. finalizatory są wykonywane przez wątek demona obsługujący kolejkę finalizacji. Jeśli wątek finalizatora nie nadąża za kolejką finalizacji, sterty Java mogą się zapełnić i tego typu zgłoszony wyjątek OutOfMemoryError .
Jednym ze scenariuszy, który może powodować taką sytuację, jest sytuacja, w której aplikacja tworzy wątki o wysokim priorytecie, które powodują, że kolejka finalizacji rośnie w tempie szybszym niż tempo, w jakim wątek finalizatora obsługuje tę kolejkę.
źródło
Wykonaj poniższe kroki:
Otwórz
catalina.sh
z tomcat / bin.Zmień JAVA_OPTS na
Uruchom ponownie kocura
źródło
Przeczytałem gdzieś indziej - catch java.lang.OutOfMemoryError i w bloku catch możesz zwolnić wszystkie zasoby, o których wiesz, że mogą zużywać dużo pamięci, zamknąć połączenia i tak dalej, a następnie wykonaj
System.gc()
następnie ponownie cokolwiek zamierzałeś to zrobić.Innym sposobem jest to, chociaż nie wiem, czy to zadziała, ale obecnie testuję, czy zadziała w mojej aplikacji.
Chodzi o to, aby wykonać czyszczenie pamięci przez wywołanie System.gc (), o której wiadomo, że zwiększa wolną pamięć. Możesz to nadal sprawdzać po wykonaniu kodu pożerającego pamięć.
źródło
Prostym sposobem rozwiązania
OutOfMemoryError
w Javie jest zwiększenie maksymalnego rozmiaru sterty za pomocą opcji JVM-Xmx512M
, co natychmiast rozwiąże błąd OutOfMemoryError. Jest to moje preferowane rozwiązanie, gdy otrzymuję OutOfMemoryError w Eclipse, Maven lub ANT podczas budowania projektu, ponieważ w oparciu o rozmiar projektu można łatwo zabraknąć pamięci.Oto przykład zwiększania maksymalnego rozmiaru sterty JVM, a także lepiej zachować stosunek -Xmx do -Xms 1: 1 lub 1: 1,5, jeśli ustawiasz rozmiar sterty w aplikacji Java.
export JVM_ARGS="-Xms1024m -Xmx1024m"
Link referencyjny
źródło
Domyślnie do programowania JVM używa małego rozmiaru i małej konfiguracji dla innych funkcji związanych z wydajnością. Ale w przypadku produkcji można dostroić np. (Dodatkowo może istnieć konfiguracja specyficzna dla serwera aplikacji) -> (Jeśli nadal nie ma wystarczającej ilości pamięci do zaspokojenia żądania i sterty osiągnęły już maksymalny rozmiar, wystąpi błąd OutOfMemoryError)
Na przykład: Na platformie Linux dla trybu produkcyjnego preferowane ustawienia.
Po pobraniu i skonfigurowaniu serwera w ten sposób http://www.ehowstuff.com/how-to-install-and-setup-apache-tomcat-8-on-centos-7-1-rhel-7/
1. utwórz plik setenv.sh w folderze / opt / tomcat / bin /
2. Otwórz i zapisz te parametry, aby ustawić preferowany tryb.
3)
service tomcat restart
źródło
Napotkałem ten sam problem z wielkością sterty Java.
Mam dwa rozwiązania, jeśli używasz java 5 (1.5).
po prostu zainstaluj jdk1.6 i przejdź do preferencji eclipse i ustaw ścieżkę jre w wersji jav1 1.6 po zainstalowaniu.
Sprawdź swój argument maszyny wirtualnej i niech będzie, czymkolwiek jest. wystarczy dodać jeden wiersz poniżej wszystkich argumentów obecnych w argumentach VM jako -Xms512m -Xmx512m -XX: MaxPermSize = ... m (192m).
Myślę, że to zadziała ...
źródło
Jeśli musisz monitorować zużycie pamięci w czasie wykonywania,
java.lang.management
oferty pakietowe,MBeans
które można wykorzystać do monitorowania pul pamięci w maszynie Wirtualnej (np. Przestrzeń eden, generowanie w ten sposób itp.), A także zachowanie usuwania śmieci.Ilość wolnego miejsca na stosie zgłaszana przez te komponenty MBean będzie się znacznie różnić w zależności od zachowania GC, szczególnie jeśli twoja aplikacja generuje wiele obiektów, które są później GC-ed. Jednym z możliwych podejść jest monitorowanie wolnej przestrzeni sterty po każdym pełnym GC, którego możesz użyć do podjęcia decyzji o zwolnieniu pamięci przez utrwalenie obiektów.
Ostatecznie najlepszym rozwiązaniem jest ograniczenie w jak największym stopniu przechowywania pamięci, a wydajność pozostaje akceptowalna. Jak wspomniano w poprzednim komentarzu, pamięć jest zawsze ograniczona, ale Twoja aplikacja powinna mieć strategię radzenia sobie z wyczerpaniem pamięci.
źródło
Zauważ, że jeśli potrzebujesz tego w sytuacji wdrażania, rozważ użycie Java WebStart (z wersją „ondisk”, a nie sieciową - możliwe w Javie 6u10 i nowszych), ponieważ pozwala ona na podanie różnych argumentów dla JVM w sposób krzyżowy sposób platformy.
W przeciwnym razie będziesz potrzebować programu uruchamiającego specyficznego dla systemu operacyjnego, który ustawia potrzebne argumenty.
źródło
Jeśli ten problem występuje w Wildfly 8 i JDK1.8, musimy określić ustawienia MaxMetaSpace zamiast ustawień PermGen.
Na przykład musimy dodać poniższą konfigurację w pliku setenv.sh wildfly.
JAVA_OPTS="$JAVA_OPTS -XX:MaxMetaspaceSize=256M"
Aby uzyskać więcej informacji, sprawdź problem z kupą Wildfly
źródło
Jeśli chodzi o netbeans, możesz ustawić maksymalny rozmiar sterty, aby rozwiązać problem.
Przejdź do „Uruchom”, a następnie -> „Ustaw konfigurację projektu” -> „Dostosuj” -> „Uruchom” wyskakującego okna -> „Opcja VM” -> wypełnij „-Xms2048m -Xmx2048m” .
źródło
Kontynuując przydzielanie i przechowywanie odniesień do obiektu, zapełnisz dowolną ilość pamięci.
Jedną z opcji jest wykonanie przezroczystego zamykania i otwierania pliku, gdy zmieniają zakładki (przytrzymujesz tylko wskaźnik do pliku, a gdy użytkownik przełącza zakładkę, zamykasz i czyścisz wszystkie obiekty ... spowoduje to wolniejszą zmianę pliku ... ale ...) i być może przechowuj tylko 3 lub 4 pliki w pamięci.
Inną rzeczą, którą powinieneś zrobić, jest to, że kiedy użytkownik otwiera plik, ładuje go i przechwytuje dowolny OutOfMemoryError, a następnie (ponieważ nie można go otworzyć) zamknąć ten plik, wyczyścić jego obiekty i ostrzec użytkownika, że powinien zamknąć nieużywany akta.
Twój pomysł na dynamiczne rozszerzanie pamięci wirtualnej nie rozwiązuje problemu, ponieważ maszyna ma ograniczone zasoby, więc powinieneś być ostrożny i zajmować się problemami z pamięcią (a przynajmniej bądź ostrożny z nimi).
Kilka wskazówek, które widziałem podczas wycieków pamięci to:
-> Pamiętaj, że jeśli włożysz coś do kolekcji, a następnie zapomnisz o tym, nadal będziesz mieć silne odniesienie do tego, więc zlikwiduj kolekcję, wyczyść ją lub zrób coś z tym ... jeśli nie, znajdziesz wyciek pamięci trudny do znalezienia.
-> Być może użycie kolekcji ze słabymi referencjami (słaba mapa ...) może pomóc w problemach z pamięcią, ale musisz być ostrożny, ponieważ może się okazać, że obiekt, którego szukasz, został zebrany.
-> Innym pomysłem, jaki znalazłem, jest opracowanie trwałej kolekcji, która przechowywana jest na obiektach bazy danych, które są najmniej używane i ładowane w sposób przezroczysty. To prawdopodobnie najlepsze podejście ...
źródło
Jeśli wszystko inne zawiedzie, oprócz zwiększenia maksymalnego rozmiaru sterty spróbuj również zwiększyć rozmiar wymiany. W przypadku systemu Linux odpowiednie instrukcje można znaleźć na stronie https://linuxize.com/post/create-a-linux-swap-file/ .
Może to pomóc, jeśli np. Kompilujesz coś dużego na wbudowanej platformie.
źródło