Postępowanie z błędem „java.lang.OutOfMemoryError: PermGen space”


1222

Ostatnio napotkałem ten błąd w mojej aplikacji internetowej:

java.lang.OutOfMemoryError: Przestrzeń PermGen

Jest to typowa aplikacja Hibernate / JPA + IceFaces / JSF działająca na Tomcat 6 i JDK 1.6. Najwyraźniej może się to zdarzyć po kilkukrotnym ponownym wdrożeniu aplikacji.

Co go powoduje i co można zrobić, aby tego uniknąć? Jak rozwiązać problem?


Walczyłem o to od wielu godzin, ale nie mam dobrych wiadomości. Zobacz moje powiązane pytanie: stackoverflow.com/questions/1996088/ ... Nadal możesz mieć przeciek pamięci, np. Klasy nie są usuwane, ponieważ twoja aplikacja WebAppClassLoader nie jest usuwana (ma zewnętrzne odniesienie, które nie jest czyszczone). zwiększenie PermGen opóźni tylko OutOfMemoryError, a zezwolenie na odśmiecanie klas jest warunkiem koniecznym, ale nie będzie odśmiecać klas, jeśli moduł ładujący klasy nadal ma do nich odniesienia.
Eran Medan

Wystąpił ten błąd podczas dodawania taglib displayowego . Usunięcie również rozwiązało błąd. Dlaczego tak?
masT

Jak na to wpadłeś?
Thorbjørn Ravn Andersen

13
użyj JDK 1.8: þ witamy w MetaSpace
Rytek

Jeśli używasz systemu Windows, postępuj zgodnie z tymi instrukcjami zamiast próbować ustawiać flagi ręcznie w plikach konfiguracyjnych. To właściwie ustawia wartości rejestru, które będą wywoływane przez Tomcat podczas działania. stackoverflow.com/questions/21104340/…
MacGyver

Odpowiedzi:


563

Rozwiązaniem było dodanie tych flag do wiersza poleceń JVM podczas uruchamiania Tomcat:

-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled

Możesz to zrobić, zamykając usługę tomcat, a następnie przechodząc do katalogu Tomcat / bin i uruchamiając tomcat6w.exe. Na karcie „Java” dodaj argumenty do pola „Opcje Java”. Kliknij „OK”, a następnie uruchom ponownie usługę.

Jeśli pojawi się błąd, określona usługa nie istnieje jako usługa zainstalowana , należy uruchomić:

tomcat6w //ES//servicename

gdzie nazwa_usługi to nazwa serwera wyświetlana w services.msc

Źródło: komentarz orx do zwinnych odpowiedzi Erica .


39
Poniższy artykuł sugeruje -XX: + UseConcMarkSweepGC i -XX: MaxPermSize = 128m. my.opera.com/karmazilla/blog/2007/03/13/…
Taylor Leese

30
-XX: + CMSPermGenSweepingEnabled Ta opcja obniża wydajność. Sprawia, że ​​każde żądanie zajmuje trzy razy więcej czasu niż zwykle w naszych systemach. Używaj ostrożnie.
Eldelshell,

10
pracował dla mnie - dziękuję - robię to na Ubuntu 10.10 z Tomcat6 - stworzyłem nowy plik: /usr/share/tomcat6/bin/setenv.sh i dodałem do tego następujący wiersz: JAVA_OPTS = "- Xms256m -Xmx512m - XX: + CMSClassUnloadingEnabled -XX: + CMSPermGenSweepingEnabled "- Zrestartowano tomcat przy użyciu: sudo /etc/init.d/tomcat6 start
sami

24
Podczas uruchamiania tomcat 6.0.29 z mojego pliku dziennika catalina.out: „Proszę użyć CMSClassUnloadingEnabled zamiast CMSPermGenSweepingEnabled w przyszłości”
knb

222
Przede wszystkim wspaniale byłoby wyjaśnić, co tak naprawdę robią te flagi. Samo powiedzenie: „rób to i ciesz się” to za mało IMHO.
Nikem

251

Lepiej spróbuj -XX:MaxPermSize=128Mniż -XX:MaxPermGen=128M.

Nie umiem dokładnie określić wykorzystania tej puli pamięci, ale ma to związek z liczbą klas załadowanych do JVM. (W ten sposób włączenie odciążania klas dla tomcat może rozwiązać problem.) Jeśli twoje aplikacje generują i kompilują klasy w trakcie pracy, bardziej prawdopodobne jest, że potrzebna będzie pula pamięci większa niż domyślna.


9
W rzeczywistości spowoduje to jedynie odroczenie OOMError. Zobacz odpowiedź rozpoczętą przez anon z dwoma linkami do blogu frankkieviet.
Rade_303

Opcje te są wyjaśnione tutaj: oracle.com/technetwork/java/javase/tech/…
amos

153

Błędy PermGen serwera aplikacji, które występują po wielu wdrożeniach, są najprawdopodobniej spowodowane odwołaniami przechowywanymi przez kontener w modułach ładujących klasy starych aplikacji. Na przykład użycie niestandardowej klasy poziomu dziennika spowoduje, że odwołania będą przechowywane przez moduł ładujący klasy serwera aplikacji. Możesz wykryć te wycieki międzyklasowe za pomocą nowoczesnych narzędzi analitycznych JVM (JDK6 +), takich jak jmap i jhat, aby sprawdzić, które klasy są nadal przechowywane w Twojej aplikacji, oraz przeprojektowując lub eliminując ich użycie. Zwykłymi podejrzanymi są bazy danych, rejestratory i inne biblioteki na poziomie podstawowej struktury.

Zobacz wycieki Classloader: przerażający wyjątek „java.lang.OutOfMemoryError: PermGen space” , a zwłaszcza jego post uzupełniający .


3
Jest to tylko prawdziwe rozwiązanie problemu, w niektórych przypadkach zbyt trudne do wdrożenia.
Rade_303

Innym bardzo dobrym źródłem jest people.apache.org/~markt/presentations/... (od menedżera wydania Tomcat !!).
gavenkoa

22
Chociaż teoretycznie może to odpowiedzieć na pytanie, lepiej byłoby zawrzeć tutaj istotne części odpowiedzi i podać odnośnik.
Joachim Sauer

68

Powszechnymi błędami, jakie popełniają ludzie, są zdania, że ​​przestrzeń sterty i przestrzeń permgena są takie same, co wcale nie jest prawdą. Na stosie może pozostać dużo miejsca, ale wciąż może zabraknąć pamięci w permgen.

Typowe przyczyny OutofMemory w PermGen to ClassLoader. Za każdym razem, gdy klasa jest ładowana do JVM, wszystkie jej metadane, wraz z Classloaderem, są przechowywane w obszarze PermGen i będą one usuwane, gdy Classloader, który je załadował, jest gotowy do odśmiecania. W przypadku, gdy Classloader ma wyciek pamięci, wszystkie załadowane przez niego klasy pozostaną w pamięci i spowodują utratę pamięci PermGen, gdy powtórzysz ją kilka razy. Klasycznym przykładem jest Java.lang.OutOfMemoryError: PermGen Space w Tomcat .

Teraz są dwa sposoby rozwiązania tego:
1. Znajdź przyczynę wycieku pamięci lub w przypadku wycieku pamięci.
2. Zwiększ rozmiar PermGen Space za pomocą parametrów JVM -XX:MaxPermSizei -XX:PermSize.

Możesz również sprawdzić 2 Rozwiązanie Java.lang.OutOfMemoryError w Javie, aby uzyskać więcej informacji.


3
Jak przekazać param -XX:MaxPermSize and -XX:PermSize?? Nie mogę znaleźć catalina.bat. Moja wersja tomcat to 5.5.26.
Deckard,

Jak znaleźć wycieki pamięci modułu ładującego klasy? Czy polecasz jakieś narzędzie?
Amit

@amit, aby zobaczyć zalecenia dotyczące narzędzi, zobacz odpowiedź wiki społeczności na to pytanie.
Barett,

@Deckard przechodzi do katalogu Tomcat / bin i uruchamia tomcat6w.exe. Na karcie „Java” dodaj argumenty do pola „Opcje Java”. Kliknij „OK”
Zeb,

43

Użyj parametru wiersza polecenia -XX:MaxPermSize=128mdla Sun JVM (oczywiście zastępując 128 dowolnym potrzebnym rozmiarem).


9
Jedynym problemem jest to, że opóźniasz to, co nieuniknione - w pewnym momencie zabraknie ci również miejsca. To świetne pragmatyczne rozwiązanie, ale nie rozwiązuje go na stałe.
Tim Howland,

to samo dzieje się w Eclipse i za każdym razem, gdy masz dużo dynamicznego ładowania klas. osoby ładujące klasy nie są usuwane i żyją w stałym pokoleniu na całą wieczność
Matt

1
Skończyło mi się PermGen podczas wykonywania szczególnie dużego zadania Hudsona ... to naprawiło to dla mnie.
HDave

10
@ TimHowland, może to być trwałe rozwiązanie, jeśli główną przyczyną nie jest wyciek modułu ładującego, tylko zbyt wiele klas / danych statycznych w Twojej aplikacji internetowej.
Péter Török,

otrzymałem ten sam problem co HDave podczas budowania Jenkins / Hudson ze źródła.
louisgab

38

Spróbuj, -XX:MaxPermSize=256ma jeśli będzie się powtarzał, spróbuj-XX:MaxPermSize=512m


56
a jeśli nadal będzie występować, spróbuj XX:MaxPermSize=1024m:)
igo

38
a jeśli nadal będzie występować, spróbuj XX: MaxPermSize = 2048m :)
Thomas

16
A jeśli nadal będzie się powtarzać, przemyśl swoją aplikację !! Lub spróbuj XX: MaxPermSize = 4096m :)
Jonathan Airey

17
możesz też spróbować 8192 m, ale to trochę przesada
Jacek Pietal

12
Rzeczywiście, przesada - 640KB powinno wystarczyć każdemu!
Joel Purra

28

I dodał -XX: MaxPermSize = 128m (można eksperymentować, które działa najlepiej) do Argumenty VM jako Używam Eclipse IDE. W większości JVM domyślny rozmiar PermSize to około 64 MB, co kończy się brakiem pamięci, jeśli w projekcie jest zbyt wiele klas lub ogromna liczba ciągów.

W przypadku zaćmienia opisano to również w odpowiedzi .

KROK 1 : Kliknij dwukrotnie serwer tomcat na karcie Serwery

wprowadź opis zdjęcia tutaj

KROK 2 : Otwórz Conf konf. I dodaj -XX: MaxPermSize = 128mdo końca istniejących argumentów VM .

wprowadź opis zdjęcia tutaj


1
Dziękujemy za najlepszą szczegółową odpowiedź (Uwaga: kliknij „Otwórz konfigurację uruchamiania”, aby otworzyć okno „edycja konfiguracji” ... ale użyłem następujących parametrów: „-XX: + CMSClassUnloadingEnabled -XX: + CMSPermGenSweepingEnabled”
Chris Sim

23

Odwracam głowę od tego problemu podczas wdrażania i cofania również złożonej aplikacji internetowej i pomyślałem, że dodam wyjaśnienie i moje rozwiązanie.

Kiedy wdrażam aplikację na Apache Tomcat, tworzony jest nowy ClassLoader dla tej aplikacji. ClassLoader jest następnie używany do ładowania wszystkich klas aplikacji, a po cofnięciu wszystko powinno ładnie zniknąć. Jednak w rzeczywistości nie jest to takie proste.

Jedna lub więcej klas utworzonych podczas życia aplikacji internetowej zawiera odwołanie statyczne, które gdzieś wzdłuż linii odwołuje się do ClassLoadera. Ponieważ referencja jest pierwotnie statyczna, żadna ilość czyszczenia pamięci nie wyczyści tej referencji - ClassLoader i wszystkie klasy, które są ładowane, pozostaną.

Po kilku ponownych wdrożeniach napotykamy błąd OutOfMemoryError.

Teraz stało się to dość poważnym problemem. Mogłem się upewnić, że Tomcat zostanie zrestartowany po każdym ponownym wdrożeniu, ale spowoduje to usunięcie całego serwera, a nie tylko aplikacji, co często nie jest możliwe.

Zamiast tego stworzyłem rozwiązanie w kodzie, które działa na Apache Tomcat 6.0. Nie testowałem na żadnym innym serwerze aplikacji i muszę podkreślić, że prawdopodobnie nie zadziała to bez modyfikacji na żadnym innym serwerze aplikacji .

Chciałbym również powiedzieć, że osobiście nienawidzę tego kodu, i że nikt nie powinien używać go jako „szybkiej poprawki”, jeśli istniejący kod można zmienić w celu użycia odpowiednich metod zamykania i czyszczenia . Należy go użyć tylko wtedy, gdy istnieje biblioteka zewnętrzna, od której zależy Twój kod (w moim przypadku był to klient RADIUS), który nie zapewnia możliwości czyszczenia własnych odniesień statycznych.

W każdym razie, dalej z kodem. Powinno to zostać wywołane w miejscu, w którym aplikacja się wdraża - na przykład metoda zniszczenia serwletu lub (lepsze podejście) metoda kontekstDestroyed ServletContextListener.

//Get a list of all classes loaded by the current webapp classloader
WebappClassLoader classLoader = (WebappClassLoader) getClass().getClassLoader();
Field classLoaderClassesField = null;
Class clazz = WebappClassLoader.class;
while (classLoaderClassesField == null && clazz != null) {
    try {
        classLoaderClassesField = clazz.getDeclaredField("classes");
    } catch (Exception exception) {
        //do nothing
    }
    clazz = clazz.getSuperclass();
}
classLoaderClassesField.setAccessible(true);

List classes = new ArrayList((Vector)classLoaderClassesField.get(classLoader));

for (Object o : classes) {
    Class c = (Class)o;
    //Make sure you identify only the packages that are holding references to the classloader.
    //Allowing this code to clear all static references will result in all sorts
    //of horrible things (like java segfaulting).
    if (c.getName().startsWith("com.whatever")) {
        //Kill any static references within all these classes.
        for (Field f : c.getDeclaredFields()) {
            if (Modifier.isStatic(f.getModifiers())
                    && !Modifier.isFinal(f.getModifiers())
                    && !f.getType().isPrimitive()) {
                try {
                    f.setAccessible(true);
                    f.set(null, null);
                } catch (Exception exception) {
                    //Log the exception
                }
            }
        }
    }
}

classes.clear();

Wiem, że minęło ponad 8 lat, odkąd to napisałem, ale gdzieś od tego czasu znalazłem głębszą przyczynę i rozwiązanie. Było tak, ponieważ podczas gdy wszystkie klasy w aplikacji internetowej są własnością kontekstowego modułu ładującego klasy, wątek, który wywołuje wywołanie zwrotne uruchamiania i zamykania, jest własnością nadrzędnego modułu ładującego klasy. Oznacza to, że jeśli kod zamykający zainicjuje zmienną lokalną wątku, spowoduje to, że nadrzędny moduł ładujący ostatecznie utrzyma odwołanie do kontekstowego modułu ładującego, co uniemożliwi dobre czyszczenie.
Edward Torbett,

Na szczęście istnieje bardzo prosta poprawka - przenieś cały kod obecnie w metodzie zamykania do metody uruchamiania nowego obiektu Thread. Następnie w metodzie zamykania rozpocznij ten wątek i poczekaj na jego zakończenie. Kod czyszczenia zostanie wykonany identycznie, ale wszelkie zmienne lokalne wątku pozostaną powiązane z modułem ładującym klasy kontekstu zamiast przeciekać.
Edward Torbett,

20

Komunikat java.lang.OutOfMemoryError: PermGenkosmiczny wskazuje, że obszar pamięci stałej generacji jest wyczerpany.

Wszelkie aplikacje Java mogą używać ograniczonej ilości pamięci. Dokładna ilość pamięci, której może użyć konkretna aplikacja, jest określona podczas uruchamiania aplikacji.

Pamięć Java jest podzielona na różne regiony, które można zobaczyć na poniższym obrazie:

wprowadź opis zdjęcia tutaj

Metaspace: rodzi się nowa przestrzeń pamięci

JVK JDK 8 HotSpot wykorzystuje teraz pamięć natywną do reprezentacji metadanych klasy i nazywa się Metaspace; podobny do Oracle JRockit i IBM JVM's.

Dobrą wiadomością jest to, że oznacza to, że nie będzie już więcej java.lang.OutOfMemoryError: PermGenproblemów z przestrzenią i nie będzie już konieczne dostrajanie i monitorowanie tej przestrzeni pamięci za pomocą Java_8_Download lub wyższej.


17

1) Zwiększanie wielkości pamięci PermGen

Pierwszą rzeczą, jaką można zrobić, jest zwiększenie wielkości powierzchni sterty stałej generacji. Nie można tego zrobić przy użyciu zwykłych argumentów JVM –Xms (ustaw początkowy rozmiar sterty) i –Xmx (ustaw maksymalny rozmiar sterty), ponieważ, jak wspomniano, przestrzeń sterty stałej generacji jest całkowicie oddzielna od zwykłej przestrzeni sterty Java, a te argumenty są ustawione przestrzeń dla tej zwykłej przestrzeni sterty Java. Istnieją jednak podobne argumenty, których można użyć (przynajmniej w przypadku Jvms Sun / OpenJDK), aby zwiększyć rozmiar sterty generacji stałej:

 -XX:MaxPermSize=128m

Domyślnie 64m.

2) Włącz zamiatanie

Innym sposobem na zadbanie o to na dobre jest umożliwienie rozładowania klas, aby Twój PermGen nigdy się nie kończył:

-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled

Takie rzeczy w przeszłości działały na mnie magicznie. Jedną rzeczą jest jednak znaczna kompromis w wydajności korzystania z nich, ponieważ przemiatanie permgenem wykona dodatkowe 2 żądania dla każdego twojego żądania lub coś podobnego. Musisz zrównoważyć swoje wykorzystanie z kompromisami.

Szczegóły tego błędu można znaleźć.

http://faisalbhagat.blogspot.com/2014/09/java-outofmemoryerror-permgen.html


Świetny post z @faisalbhagat faisalbhagat.blogspot.com/2014/09/…
leomeurer

Opcja 2 jest świetna, ale ostrzegam, że nie należy jej używać w środowiskach produkcyjnych. Zazwyczaj najlepiej jest trzymać go tylko w środowiskach programistycznych. Jednak PermGen został usunięty z Java 8 openjdk.java.net/jeps/122
hdost


14

Miałem problem, o którym tu mówimy, mój scenariusz to eclipse-helios + tomcat + jsf, a to, co robiłeś, polega na stworzeniu prostej aplikacji do tomcat. Pokazałem tutaj ten sam problem, rozwiązałem go w następujący sposób.

W Eclipse przejdź do zakładki serwery, kliknij dwukrotnie zarejestrowany serwer w moim przypadku tomcat 7.0, otwiera mój serwer plików Ogólne informacje rejestracyjne. W sekcji „Informacje ogólne” kliknij link „Otwórz konfigurację uruchamiania” , otwiera to wykonanie opcji serwera na karcie Argumenty w argumentach VM dodanych na końcu te dwa wpisy

-XX: MaxPermSize = 512m
-XX: PermSize = 512m

i gotowy.


14

Najprostszą odpowiedzią jest obecnie użycie Java 8.

Nie rezerwuje już pamięci wyłącznie na przestrzeń PermGen, pozwalając na połączenie pamięci PermGen ze zwykłą pulą pamięci.

Pamiętaj, że będziesz musiał usunąć wszystkie niestandardowe -XXPermGen...=...parametry uruchamiania JVM, jeśli nie chcesz, aby Java 8 narzekało, że nic nie robią.


Witaj, ta odpowiedź została już udzielona: stackoverflow.com/a/22897121/505893 . Proszę usunąć swoją odpowiedź, dla jasności. W razie potrzeby możesz poprawić odpowiedź, o której wspomniałem. Dzięki;)
niebieskawy

6
@bluish Dziękujemy za zwrócenie na to uwagi; jednak ta odpowiedź jest bardzo ważna w przypadku mówienia o wyjątkach OutOfMemory i wyciekających metadanych. Nie wspomina również o bardzo ważnych punktach usunięcia opcji PermGen. Krótko mówiąc, nie jestem pewien, czy poprawiłbym odpowiedź, ale raczej przepisałem ją. Gdyby to był tylko krótki retusz, czułbym się mniej niepewny, ale wygląda na to, że byłby czymś więcej niż szybkim retuszem i nie chciałbym obrażać oryginalnego autora. Mimo to ta lista odpowiedzi jest psim bałaganem i być może zabicie mojego postu byłoby najlepsze.
Edwin Buck

8
  1. Otwórz tomcat7w z katalogu bin Tomcat lub wpisz Monitor Tomcat w menu Start (otworzy się okno z zakładkami z różnymi informacjami o usługach).
  2. W polu tekstowym Opcje Java dodaj ten wiersz:

    -XX:MaxPermSize=128m
  3. Ustaw początkową pulę pamięci na 1024 (opcjonalnie).
  4. Ustaw maksymalną pulę pamięci na 1024 (opcjonalnie).
  5. Kliknij OK.
  6. Uruchom ponownie usługę Tomcat.

6

Błąd przestrzeni perm gen występuje z powodu użycia dużej przestrzeni zamiast przestrzeni przewidzianej przez JVM do wykonania kodu.

Najlepszym rozwiązaniem tego problemu w systemach operacyjnych UNIX jest zmiana konfiguracji w pliku bash. Poniższe kroki rozwiązują problem.

Uruchom polecenie gedit .bashrcna terminalu.

Utwórz JAVA_OTPSzmienną o następującej wartości:

export JAVA_OPTS="-XX:PermSize=256m -XX:MaxPermSize=512m"

Zapisz plik bash. Uruchom polecenie exec bash na terminalu. Uruchom ponownie serwer.

Mam nadzieję, że to podejście zadziała w przypadku twojego problemu. Jeśli używasz wersji Java niższej niż 8, ten problem występuje czasami. Ale jeśli używasz Java 8, problem nigdy nie występuje.


5

Zwiększenie wielkości stałej generacji lub poprawienie parametrów GC NIE pomoże, jeśli masz prawdziwy wyciek pamięci. Jeśli używana aplikacja lub biblioteka innej firmy używa, nieszczelne moduły ładujące, jedynym prawdziwym i trwałym rozwiązaniem jest znalezienie tego wycieku i usunięcie go. Istnieje wiele narzędzi, które mogą ci pomóc, jednym z najnowszych jest Plumbr , który właśnie wydał nową wersję z wymaganymi możliwościami.


5

Również jeśli używasz log4j w swojej aplikacji internetowej, sprawdź ten akapit w dokumentacji log4j .

Wygląda na to, że jeśli korzystasz PropertyConfigurator.configureAndWatch("log4j.properties"), powoduje to wycieki pamięci podczas cofania aplikacji internetowej.


4

Mam kombinację Hibernacji + Eclipse RCP, próbowałem użyć -XX:MaxPermSize=512mi -XX:PermSize=512mwydaje się, że działa dla mnie.


4

Set -XX:PermSize=64m -XX:MaxPermSize=128m. Później możesz również spróbować zwiększyć MaxPermSize. Mam nadzieję, że to zadziała. To samo działa dla mnie. Ustawienie tylko MaxPermSizemi nie działało.


4

Próbowałem kilku odpowiedzi i jedyną rzeczą, która ostatecznie wykonała to zadanie, była konfiguracja wtyczki kompilatora w pom:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>2.3.2</version>
    <configuration>
        <fork>true</fork>
        <meminitial>128m</meminitial>
        <maxmem>512m</maxmem>
        <source>1.6</source>
        <target>1.6</target>
        <!-- prevent PermGen space out of memory exception -->
        <!-- <argLine>-Xmx512m -XX:MaxPermSize=512m</argLine> -->
    </configuration>
</plugin>

mam nadzieję, że to pomoże.


„argLine” nie jest rozpoznawane przez maven-compiler-plugin 2.4. obsługuje tylko „compilerArgument”, co daje błąd: <gument_kompilatora> -XX: MaxPermSize = 256m </compilerArgument> [BŁĄD] Błąd podczas wykonywania javac, ale nie można przeanalizować błędu: javac: nieprawidłowa flaga: -XX: MaxPermSize = 256m Wykorzystanie : javac <options> <pliki źródłowe>
Alex

Jeśli w fazie kompilacji kończy się permgen, ustaw <kompilatorArgument> na wtyczce kompilatora maven. Jeśli w testach jednostkowych kończy się permgen, ustaw <argLine> w wtyczce maven-surefire
qwerty

4

rozwiązałem to również dla mnie; Zauważyłem jednak, że czasy restartu serwletów były znacznie gorsze, więc chociaż był lepszy w produkcji, był nieco trudny w rozwoju.


3

Konfiguracja pamięci zależy od charakteru aplikacji.

Co robisz?

Jaka jest liczba transakcji?

Ile danych ładujesz?

itp.

itp.

itp

Prawdopodobnie możesz profilować aplikację i rozpocząć czyszczenie niektórych modułów z aplikacji.

Najwyraźniej może się to zdarzyć po kilkukrotnym ponownym wdrożeniu aplikacji

Tomcat wdrożył na gorąco, ale zużywa pamięć. Spróbuj ponownie uruchomić pojemnik raz na jakiś czas. Będziesz także musiał znać ilość pamięci potrzebną do uruchomienia w trybie produkcyjnym, wydaje się, że to dobry czas na te badania.


3

Mówią, że najnowsza wersja Tomcat (6.0.28 lub 6.0.29) znacznie lepiej radzi sobie z ponownym wdrażaniem serwletów .


3

Napotkałem dokładnie ten sam problem, ale niestety żadne z zaproponowanych rozwiązań nie zadziałało. Problem nie wystąpił podczas wdrażania, a ja nie robiłem żadnych gorących wdrożeń.

W moim przypadku problem pojawiał się za każdym razem w tym samym momencie podczas uruchamiania mojej aplikacji internetowej, podczas łączenia (przez hibernację) z bazą danych.

Ten link (wspomniany również wcześniej) zawierał wystarczającą liczbę elementów wewnętrznych, aby rozwiązać problem. Przeniesienie jdbc- (mysql) -driver z WEB-INF do folderu jre / lib / ext / wydaje się rozwiązać problem. To nie jest idealne rozwiązanie, ponieważ aktualizacja do nowszej wersji JRE wymaga ponownej instalacji sterownika. Kolejnym kandydatem, który może powodować podobne problemy, jest log4j, więc możesz również chcieć go przenieść


Jeśli nie chcesz dołączać sterownika do jre / lib / ext, prawdopodobnie możesz uzyskać takie same wyniki, włączając sterownik do ścieżki klas startowego kontenera. java -cp /path/to/jdbc-mysql-driver.jar:/path/to/container/bootstrap.jar container.Start
Scot

3

Pierwszym krokiem w takim przypadku jest sprawdzenie, czy GC może zwolnić klasy z PermGen. Standardowa JVM jest pod tym względem raczej konserwatywna - klasy rodzą się, aby żyć wiecznie. Po załadowaniu klasy pozostają w pamięci, nawet jeśli żaden kod ich już nie używa. Może to stać się problemem, gdy aplikacja tworzy dynamicznie wiele klas, a generowane klasy nie są potrzebne przez dłuższy czas. W takim przypadku pomocne może być zwolnienie przez JVM definicji klas. Można to osiągnąć, dodając tylko jeden parametr konfiguracyjny do skryptów uruchamiania:

-XX:+CMSClassUnloadingEnabled

Domyślnie jest ustawiony na false, więc aby to włączyć, musisz jawnie ustawić następującą opcję w opcjach Java. Jeśli włączysz CMSClassUnloadingEnabled, GC przeczesuje również PermGen i usunie klasy, które nie są już używane. Pamiętaj, że ta opcja będzie działać tylko wtedy, gdy UseConcMarkSweepGC jest również włączony przy użyciu poniższej opcji. Dlatego podczas uruchamiania ParallelGC lub, na wszelki wypadek, Serial GC, upewnij się, że ustawiłeś GC na CMS, określając:

-XX:+UseConcMarkSweepGC

3

Przypisanie większej ilości pamięci Tomcat NIE jest właściwym rozwiązaniem.

Prawidłowym rozwiązaniem jest przeprowadzenie czyszczenia po zniszczeniu i odtworzeniu kontekstu (wdrożenie na gorąco). Rozwiązaniem jest powstrzymanie wycieków pamięci.

Jeśli serwer Tomcat / Webapp informuje cię, że nie można wyrejestrować sterowników (JDBC), to wyrejestruj je. To zatrzyma wycieki pamięci.

Możesz utworzyć ServletContextListener i skonfigurować go w pliku web.xml. Oto przykładowy ServletContextListener:

import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Enumeration;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

import org.apache.log4j.Logger;

import com.mysql.jdbc.AbandonedConnectionCleanupThread;

/**
 * 
 * @author alejandro.tkachuk / calculistik.com
 *
 */
public class AppContextListener implements ServletContextListener {

    private static final Logger logger = Logger.getLogger(AppContextListener.class);

    @Override
    public void contextInitialized(ServletContextEvent arg0) {
        logger.info("AppContextListener started");
    }

    @Override
    public void contextDestroyed(ServletContextEvent arg0) {
        logger.info("AppContextListener destroyed");

        // manually unregister the JDBC drivers
        Enumeration<Driver> drivers = DriverManager.getDrivers();
        while (drivers.hasMoreElements()) {
            Driver driver = drivers.nextElement();
            try {
                DriverManager.deregisterDriver(driver);
                logger.info(String.format("Unregistering jdbc driver: %s", driver));
            } catch (SQLException e) {
                logger.info(String.format("Error unregistering driver %s", driver), e);
            }

        }

        // manually shutdown clean up threads
        try {
            AbandonedConnectionCleanupThread.shutdown();
            logger.info("Shutting down AbandonedConnectionCleanupThread");
        } catch (InterruptedException e) {
            logger.warn("SEVERE problem shutting down AbandonedConnectionCleanupThread: ", e);
            e.printStackTrace();
        }        
    }
}

I tutaj możesz go skonfigurować w pliku web.xml:

<listener>
    <listener-class>
        com.calculistik.mediweb.context.AppContextListener 
    </listener-class>
</listener>  

2

„Oni” są w błędzie, ponieważ korzystam z wersji 6.0.29 i mam ten sam problem, nawet po ustawieniu wszystkich opcji. Jak powiedział Tim Howland powyżej, te opcje odkładają tylko nieuniknione. Pozwalają mi ponownie wdrożyć 3 razy, zanim trafię w błąd, a nie za każdym razem, gdy dokonam ponownego wdrożenia.


2

W przypadku, gdy są coraz to w IDE Eclipse, nawet po ustawieniu parametrów --launcher.XXMaxPermSize, -XX:MaxPermSizeitp, nadal jeśli otrzymujesz ten sam błąd, to najbardziej prawdopodobne jest to, że Eclipse jest za pomocą wersji buggy środowiska JRE, które zostały zainstalowane przez niektóre aplikacje innych firm i ustawione na domyślne. Te błędne wersje nie pobierają parametrów PermSize, więc bez względu na to, co ustawisz, nadal występują te błędy pamięci. Zatem w swoim eclipse.ini dodaj następujące parametry:

-vm <path to the right JRE directory>/<name of javaw executable>

Upewnij się również, że ustawiłeś domyślne środowisko JRE w preferencjach w zaćmieniu na prawidłową wersję Java.


2

Jedynym sposobem, który działał dla mnie, był JRockit JVM. Mam MyEclipse 8.6.

Sterta JVM przechowuje wszystkie obiekty wygenerowane przez działający program Java. Java używa newoperatora do tworzenia obiektów, a pamięć na nowe obiekty jest przydzielana na stercie w czasie wykonywania. Wyrzucanie elementów bezużytecznych to mechanizm automatycznego zwalniania pamięci zawartej w obiektach, do których program nie odwołuje się.


2

Miałem podobny problem. Mój to projekt oparty na wstrzykiwaniu zależności JDK 7 + Maven 3.0.2 + Struts 2.0 + Google GUICE.

Ilekroć próbowałem uruchomić mvn clean packagepolecenie, pojawiał się następujący błąd i pojawiał się komunikat „BUILD FAILURE”

org.apache.maven.surefire.util.SurefireReflectionException: java.lang.reflect.InvocationTargetException; wyjątek zagnieżdżony to java.lang.reflect.InvocationTargetException: null java.lang.reflect.InvocationTargetException Przyczyna: java.lang.OutOfMemoryError: PermGen space

Wypróbowałem wszystkie powyższe przydatne porady i wskazówki, ale niestety żadna z nich nie zadziałała. To, co zadziałało, zostało opisane krok po kroku poniżej: =>

  1. Przejdź do pliku pom.xml
  2. Szukaj <artifactId>maven-surefire-plugin</artifactId>
  3. Dodaj nowy <configuration>element, a następnie <argLine>element podrzędny, w którym przekaż, -Xmx512m -XX:MaxPermSize=256mjak pokazano poniżej =>

<configuration> <argLine>-Xmx512m -XX:MaxPermSize=256m</argLine> </configuration>

Mam nadzieję, że to pomoże, miłego programowania :)

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.