“Java.lang.OutOfMemoryError: PermGen alanı” hatası ile ilgilenme


1222

Son zamanlarda web uygulamamda bu hatayla karşılaştım:

java.lang.OutOfMemoryError: PermGen alanı

Tomcat 6 ve JDK 1.6 üzerinde çalışan tipik bir Hibernate / JPA + IceFaces / JSF uygulamasıdır. Görünüşe göre bu, bir uygulamayı birkaç kez yeniden konuşlandırdıktan sonra ortaya çıkabilir.

Buna ne sebep olur ve bundan kaçınmak için ne yapılabilir? Sorunu nasıl düzeltebilirim?


Bunu saatlerce savaştım ama iyi haberlerim yok. İlgili sorumu görün: stackoverflow.com/questions/1996088/… Hala bir bellek sızıntısı olabilir, örneğin WebAppClassLoader'ınız çöp toplanmadığı için sınıflar çöp toplanmaz (temizlenmeyen bir dış referansa sahiptir). PermGen'i artırmak yalnızca OutOfMemoryError'u geciktirir ve sınıf çöp toplama izin vermek bir önkoşuldur, ancak sınıf yükleyicileri hala referansları varsa sınıfları çöp toplama olmaz.
Eran Medan

Display taglib eklerken bu hatayı aldım . Bunu kaldırmak da hatayı çözdü. Neden öyle?
masT

Ve bununla nasıl karşılaştınız?
Thorbjørn Ravn Andersen

13
use JDK 1.8: þ MetaSpace'e hoş geldiniz
Rytek

Windows kullanıyorsanız, yapılandırma dosyalarında bayrakları manuel olarak ayarlamaya çalışmak yerine bu talimatları izleyin. Bu, çalışma zamanında Tomcat tarafından çağrılacak kayıt defterindeki değerleri düzgün şekilde ayarlar. stackoverflow.com/questions/21104340/…
MacGyver

Yanıtlar:


563

Çözüm, Tomcat başlatıldığında bu bayrakları JVM komut satırına eklemekti:

-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled

Bunu tomcat hizmetini kapatarak, sonra Tomcat / bin dizinine gidip tomcat6w.exe dosyasını çalıştırarak yapabilirsiniz. "Java" sekmesinin altında, "Java Seçenekleri" kutusuna bağımsız değişkenler ekleyin. "Tamam" ı tıklayın ve hizmeti yeniden başlatın.

Bir hata alırsanız , belirtilen hizmet yüklü bir hizmet olarak mevcut değildir :

tomcat6w //ES//servicename

burada hizmet adı, services.msc dosyasında görüldüğü gibi sunucunun adıdır

Kaynak: orx'un Eric'in Çevik Yanıtları hakkındaki yorumu .


39
Aşağıdaki makalede -XX: + UseConcMarkSweepGC ve -XX: MaxPermSize = 128m de önerilmektedir. my.opera.com/karmazilla/blog/2007/03/13/…
Taylor Leese

30
-XX: + CMSPermGenSweepingEnabled Bu seçenek performansı düşürür. Sistemlerimizde her isteğin normalden üç kat daha fazla zaman almasını sağlar. Dikkatli kullanın.
Eldelshell

10
benim için çalıştı - teşekkürler - Tomcat6 ile Ubuntu 10.10 üzerinde yapıyorum - Yeni bir dosya oluşturdum: /usr/share/tomcat6/bin/setenv.sh ve aşağıdaki satırı ekledi: JAVA_OPTS = "- Xms256m -Xmx512m - XX: + CMSClassUnloadingEnabled -XX: + CMSPermGenSweepingEnabled "- Kullanarak tomcat yeniden başlatıldı: sudo /etc/init.d/tomcat6 start
sami

24
Tomcat 6.0.29 başlangıcında, catalina.out log dosyamdan: "Lütfen gelecekte CMSPermGenSweepingEnabled yerine CMSClassUnloadingEnabled kullanın"
kn

222
Her şeyden önce bu bayrakların gerçekten ne yaptığını açıklamak harika olurdu. Sadece "bunu yap ve tadını çıkar" demek yeterli değildir IMHO.
Nikem

251

Denemek -XX:MaxPermSize=128Myerine denesen iyi olur -XX:MaxPermGen=128M.

Bu bellek havuzunun tam kullanımını söyleyemem, ancak JVM'ye yüklenen sınıfların sayısı ile ilgisi var. (Böylece tomcat için sınıfın boşaltılmasının etkinleştirilmesi sorunu çözebilir.) Uygulamalarınız çalışma sırasında sınıflar oluşturuyor ve derlerse, varsayılandan daha büyük bir bellek havuzuna ihtiyaç duyma olasılığı daha yüksektir.


9
Aslında, bu sadece OOMError'u erteleyecektir. Aşağıdaki cevap frankoneviet blog iki bağlantı ile anon tarafından başlatıldı.
Rade_303

Bu seçenekler burada açıklanmıştır: oracle.com/technetwork/java/javase/tech/…
amos

153

Birden çok dağıtımdan sonra meydana gelen uygulama sunucusu PermGen hataları büyük olasılıkla kapsayıcı tarafından eski uygulamalarınızın sınıf yükleyicilerine yapılan referanslardan kaynaklanır. Örneğin, özel bir günlük düzeyi sınıfı kullanmak başvuruların uygulama sunucusunun sınıf yükleyicisi tarafından tutulmasına neden olur. Bu sınıflar arası yükleyici sızıntılarını, uygulamanızda hangi sınıfların tutulmaya devam ettiğine bakmak için jmap ve jhat gibi modern (JDK6 +) JVM analiz araçlarını kullanarak ve bunların kullanımını yeniden tasarlayarak veya ortadan kaldırarak tespit edebilirsiniz. Olağan şüpheliler veritabanları, kaydediciler ve diğer temel çerçeve düzeyindeki kütüphanelerdir.

Bkz. Classloader sızıntıları: korkunç "java.lang.OutOfMemoryError: PermGen alanı" istisnası ve özellikle takip yazısı .


3
Bu, sadece bazı durumlarda uygulanması çok zor olan probleme gerçek bir çözümdür.
Rade_303

Bir başka çok iyi kaynak da people.apache.org/~markt/presentations/… (Tomcat sürüm yöneticisinden !!).
gavenkoa

22
Bu teorik olarak soruyu cevaplayabilirken, cevabın temel bölümlerini buraya dahil etmek ve referans için bağlantı sağlamak tercih edilir.
Joachim Sauer

68

İnsanların yaptığı yaygın hatalar, yığın alanı ve permgen uzayının aynı olduğunu düşünüyor, ki bu hiç de doğru değil. Öbekte çok fazla alanınız olabilir, ancak yine de permende bellek yetersiz olabilir.

PermGen'de OutofMemory'nin yaygın nedenleri ClassLoader'dır. Bir sınıf JVM'ye her yüklendiğinde, Classloader ile birlikte tüm meta verileri PermGen alanında tutulur ve onları yükleyen Classloader çöp toplamaya hazır olduğunda bunlar toplanır. Classloader'ın yüklediği tüm sınıflardan daha fazla bellek sızıntısı olması durumunda, bellekte kalır ve birkaç kez tekrarladığınızda permGen outofmemory'ye neden olur. Klasik örnek Java.lang.OutOfMemoryError: Tomcat'te PermGen Space'dir .

Şimdi bunu çözmenin iki yolu var:
1. Bellek Sızıntısının nedenini veya bellek sızıntısı olup olmadığını bulun.
2. JVM parametresini -XX:MaxPermSizeve kullanarak PermGen Space boyutunu artırın -XX:PermSize.

Daha fazla bilgi için Java'daki 2 Java.lang.OutOfMemoryError Çözümü'nü de kontrol edebilirsiniz .


3
Param nasıl geçilir -XX:MaxPermSize and -XX:PermSize? Bulamıyorum catalina.bat. Tomcat versiyonum 5.5.26.
Deckard

Sınıf yükleyicinin bellek sızıntıları nasıl bulunur? Herhangi bir araç tavsiye ediyor musunuz?
Amit

@amit araç önerileri için bu soruya ilişkin topluluk wiki yanıtına bakın.
Barett

@ Tomcat / bin dizinine gidip tomcat6w.exe dosyasını çalıştırın. "Java" sekmesinin altında, "Java Seçenekleri" kutusuna bağımsız değişkenler ekleyin. "Tamam" ı tıklayın
Zeb

43

-XX:MaxPermSize=128mSun JVM için komut satırı parametresini kullanın (açıkçası ihtiyacınız olan boyutta 128 yerine).


9
Tek sorun şu ki, kaçınılmaz olanı geciktiriyorsunuz - bir noktada orada da tavan boşluğunuz bitecek. Harika bir pragmatik çözüm, ancak kalıcı olarak çözmüyor.
Tim Howland

Eclipse'de aynı şey olur ve her zaman çok sayıda dinamik sınıf yüklemeniz olur. sınıf yükleyiciler tüm sonsuzluk için bertaraf edilmez ve kalıcı nesilde yaşarlar
Matt

1
Özellikle büyük bir Hudson işi yaparken PermGen'den kaçıyordum ... bu benim için düzeltildi.
HDave

10
@TimHowland, kök nedeni sınıf yükleyici sızıntısı değil, web uygulamanızda çok fazla sınıf / statik veri değilse kalıcı bir düzeltme olabilir.
Péter Török

kaynaktan jenkins / hudson oluştururken HDave ile aynı sorunu yaşadı.
louisgab

38

Deneyin -XX:MaxPermSize=256mve devam ederse, deneyin-XX:MaxPermSize=512m


56
ve hala devam ederse deneyin XX:MaxPermSize=1024m:)
igo 12:30 '

38
ve hala devam ederse XX deneyin: MaxPermSize = 2048m :)
Thomas

16
Ve eğer HALA devam ederse, başvurunuzu yeniden düşünün !! Veya XX'yi deneyin: MaxPermSize = 4096m :)
Jonathan Airey

17
Ayrıca 8192m deneyebilirsiniz ama biraz fazla thats
Jacek Pietal

12
Gerçekten aşırı - 640KB herkes için yeterli olmalı!
Joel Purra

28

Ben ekledi -XX: MaxPermSize = 128m için (eğer en iyi çalıştığını deneme yapabilirsiniz) VM argümanlar Ben Tutulma ide kullanıyorum olarak. JVM çoğunda, varsayılan PermSize etrafında 64MB çok fazla sınıf veya projede Strings büyük sayıda varsa belleğin biterse.

Tutulma için, cevapta da açıklanmaktadır .

ADIM 1 : Sunucular Sekmesinde tomcat sunucusuna çift tıklayın

resim açıklamasını buraya girin

ADIM 2 : Conf uygulamasını açın ve -XX: MaxPermSize = 128mmevcut VM tartışmalarının sonuna ekleyin .

resim açıklamasını buraya girin


1
En ayrıntılı yanıtınız için teşekkür ederiz (Not: "yapılandırmayı düzenle" penceresini açmak için "Yapılandırmayı aç" ı tıklayın ... ancak şu parametreleri kullandım: "-XX: + CMSClassUnloadingEnabled -XX: + CMSPermGenSweepingEnabled"
Chris Sim

23

Ben de karmaşık bir web uygulaması dağıtırken ve çözerken bu soruna karşı başımı eğiyordum ve bir açıklama ve çözüm ekleyeceğimi düşündüm.

Bir uygulamayı Apache Tomcat'e dağıttığımda, o uygulama için yeni bir ClassLoader oluşturulur. Daha sonra ClassLoader, uygulamanın tüm sınıflarını yüklemek için kullanılır ve çözüldüğünde, her şeyin güzelce gitmesi gerekir. Ancak, gerçekte o kadar basit değil.

Web uygulamasının ömrü boyunca oluşturulan bir veya daha fazla sınıf, çizgi boyunca bir yerde ClassLoader'a başvuran statik bir başvuru içerir. Referans başlangıçta statik olduğundan, hiçbir çöp toplama işlemi bu referansı temizlemez - ClassLoader ve yüklenen tüm sınıflar burada kalır.

Ve birkaç tekrardan sonra OutOfMemoryError ile karşılaşıyoruz.

Şimdi bu oldukça ciddi bir sorun haline geldi. Tomcat'in her yeniden konuşlandırmadan sonra yeniden başlatıldığından emin olabilirim, ancak bu, uygulamanın yeniden dağıtılmasından ziyade sunucunun tamamını kapar ve bu genellikle mümkün değildir.

Bunun yerine Apache Tomcat 6.0 üzerinde çalışan kodda bir çözüm oluşturdum. Başka bir uygulama sunucusunda test etmedim ve bunun başka bir uygulama sunucusunda değişiklik yapmadan çalışmamasının çok olası olduğunu vurgulamalıyım .

Ben de kişisel olarak bu kod nefret ve mevcut kod uygun kapatma ve temizleme yöntemleri kullanmak için değiştirilebilir eğer kimse bu "hızlı düzeltme" olarak kullanmak gerektiğini söylemek istiyorum . Kullanılması gereken tek zaman, kodunuzun bağımlı olduğu harici bir kütüphane varsa (benim durumumda, bir RADIUS istemcisiydi) kendi statik referanslarını temizlemek için bir yol sağlamaz.

Her neyse, kodla devam et. Bu, uygulamanın bir sunucu uygulamasının destroy yöntemi veya (daha iyi bir yaklaşım) ServletContextListener'ın contextDestroyed yöntemi gibi uygulamanın çözülmediği noktada çağrılmalıdır.

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

Bunu yazmamın üzerinden 8 yıl geçtiğini biliyorum, ama o zaman ve şimdi arasında daha derin bir neden ve çözüm buldum. Bu, webapp içindeki tüm sınıfların bağlam sınıf yükleyicisine ait olmasına rağmen, başlatma ve kapatma geri aramasını başlatan iş parçacığının üst sınıf yükleyiciye ait olmasıdır. Bu, kapatma kodu bir yerel iş parçacığı değişkenini başlatırsa, üst sınıf yükleyicinin bağlam sınıf yükleyicisine bir başvuru tutarak sonuçta iyi temizlemeyi önleyeceği anlamına gelir.
Edward Torbett

Neyse ki, çok basit bir düzeltme var - şu anda kapatma yöntemindeki tüm kodu yeni bir Thread nesnesinin çalıştırma yöntemine taşıyın. Ardından, kapatma yönteminde bu iş parçacığını başlatın ve tamamlanmasını bekleyin. Temizleme kodu aynı şekilde yürütülür, ancak iş parçacığı yerel değişkenleri sızıntı yerine bağlam sınıfı yükleyiciye bağlı kalır.
Edward Torbett

20

java.lang.OutOfMemoryError: PermGenUzay mesajı hafızasında Daimi Generation'in alanı tükenmiş olduğunu gösterir.

Herhangi bir Java uygulamasının sınırlı miktarda bellek kullanmasına izin verilir. Uygulamanızın kullanabileceği tam bellek miktarı, uygulama başlatılırken belirtilir.

Java belleği aşağıdaki görüntüde görülebilen farklı bölgelere ayrılmıştır:

resim açıklamasını buraya girin

Metaspace: Yeni bir hafıza alanı doğuyor

JDK 8 HotSpot JVM artık sınıf meta verilerinin temsili için yerel belleği kullanıyor ve Metaspace olarak adlandırılıyor; Oracle JRockit ve IBM JVM'lere benzer.

İyi haber şu ki, daha fazla java.lang.OutOfMemoryError: PermGenalan sorunu yok ve artık Java_8_Download veya üstünü kullanarak bu hafıza alanını ayarlamanıza ve izlemenize gerek yok .


17

1) PermGen Bellek Boyutunun Arttırılması

Birinin yapabileceği ilk şey, kalıcı nesil yığın alanının boyutunu büyütmektir. Bu, her zamanki –Xms (başlangıç ​​yığın boyutunu ayarla) ve –Xmx (maksimum yığın boyutunu ayarla) JVM bağımsız değişkenleriyle yapılamaz; Bu düzenli Java yığın alanı için alan. Bununla birlikte, kalıcı nesil yığınının boyutunu büyütmek için kullanılabilecek benzer argümanlar vardır (en azından Sun / OpenJDK jvms ile):

 -XX:MaxPermSize=128m

Varsayılan 64m'dir.

2) Süpürmeyi Etkinleştir

İyilik için bununla ilgilenmenin başka bir yolu da PermGen'in asla bitmemesi için sınıfların boşaltılmasına izin vermektir:

-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled

Böyle şeyler geçmişte benim için sihir çalıştı. Bununla birlikte, bir şey, bunları kullanırken önemli bir performans değiş tokuşu vardır, çünkü permgen süpürmeleri yaptığınız her istek veya bu hatlar boyunca bir şey için fazladan 2 istek gibi olacaktır. Kullanımınızı dengelerle dengelemeniz gerekir.

Bu hatanın ayrıntılarını bulabilirsiniz.

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



Seçenek 2 harika, ancak üretim ortamlarında kullanılmaması gerektiği konusunda uyarılmalıdır. Genellikle yalnızca geliştirme ortamlarında tutmak en iyisidir. Ancak PermGen Java 8'den kaldırıldı openjdk.java.net/jeps/122
hdost


14

Burada bahsettiğimiz sorun yaşadım, senaryom eclipse-helios + tomcat + jsf ve yaptığınız şey tomcat için basit bir uygulama yapmak. Burada da aynı sorunu gösteriyordum, şu şekilde çözdüm.

Tutulma sunucuları sekmesine gitmek kayıtlı sunucuya tomcat 7.0 çift tıklayın, dosya sunucumu açar Genel kayıt bilgileri. "Genel Bilgiler" bölümünde " Açılış yapılandırmasını aç" bağlantısına tıklayın , bu, bu iki girişin sonuna eklenen VM argümanlarındaki Bağımsız Değişkenler sekmesinde sunucu seçeneklerinin yürütülmesini açar

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

ve hazır.


14

Bu günlerde en basit cevap Java 8 kullanmaktır.

Artık yalnızca PermGen alanı için bellek ayırmaz, bu da PermGen belleğinin normal bellek havuzuyla birleşmesine izin verir.

-XXPermGen...=...Java 8'in hiçbir şey yapmadığından şikayet etmesini istemiyorsanız, standart olmayan tüm JVM başlangıç ​​parametrelerini kaldırmanız gerekeceğini unutmayın .


Merhaba, bu cevap zaten verildi: stackoverflow.com/a/22897121/505893 . Açıklık için lütfen cevabınızı silin. Gerekirse bahsettiğim yanıtı geliştirebilirsiniz. Teşekkürler;)
mavimsi

6
@bluish Bunu işaret ettiğiniz için teşekkür ederiz; ancak, bu yanıt OutOfMemoryExceptions ve sızan meta veriler hakkında konuşmaya devam ediyor. Ayrıca PermGen seçeneğinin kaldırılmasının çok önemli noktalarından da söz etmiyor. Kısacası, cevabı geliştireceğimden emin değilim, tekrar yazıyorum. Sadece hızlı bir rötuş olsaydı, daha az tereddüt hissederdim, ama hızlı bir rötuştan çok daha fazlası gibi görünüyor ve orijinal yazarı kırmaktan nefret ediyorum. Yine de, bu cevap listesi bir köpeğin dağınık bir akşam yemeği ve belki de yazımı öldürmek yine de en iyisi olurdu.
Edwin Buck

8
  1. Tomcat'in bin dizininden tomcat7w'yi açın veya başlat menüsünde Monitor Tomcat yazın (çeşitli servis bilgileri içeren sekmeli bir pencere açılır).
  2. Java Seçenekleri metin alanına şu satırı ekleyin:

    -XX:MaxPermSize=128m
  3. İlk Bellek Havuzunu 1024 olarak ayarlayın (isteğe bağlı).
  4. Maksimum Bellek Havuzu'nu 1024 olarak ayarlayın (isteğe bağlı).
  5. Tamam'ı tıklayın.
  6. Tomcat hizmetini yeniden başlatın.

6

Perm gen uzay hatası jvm yerine kod yürütmek için sağlanan boşluk yerine büyük alan kullanımı nedeniyle oluşur.

UNIX işletim sistemlerinde bu sorunun en iyi çözümü, bash dosyasındaki bazı yapılandırmaları değiştirmektir. Aşağıdaki adımlar sorunu çözmektedir.

gedit .bashrcTerminalde komutu çalıştırın .

JAVA_OTPSAşağıdaki değere sahip değişken oluşturun :

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

Bash dosyasını kaydedin. Terminalde exec bash komutunu çalıştırın. Sunucuyu yeniden başlatın.

Umarım bu yaklaşım probleminizde işe yarar. 8'den daha düşük bir Java sürümü kullanıyorsanız, bu sorun bazen oluşur. Ancak Java 8 kullanıyorsanız sorun asla oluşmaz.


5

Kalıcı Nesil boyutunu artırmak veya GC parametrelerini değiştirmek, gerçek bir bellek sızıntısı varsa yardımcı DEĞİLDİR. Uygulamanız veya kullandığı bazı 3. taraf kitaplıkları varsa, sınıf yükleyicilere sızdıran tek gerçek ve kalıcı çözüm bu sızıntıyı bulmak ve düzeltmektir. Size yardımcı olabilecek birçok araç var, son zamanlarda gerekli yeteneklere sahip yeni bir sürüm çıkaran Plumbr .


5

Ayrıca web uygulamanızda log4j kullanıyorsanız, log4j belgelerinde bu paragrafı kontrol edin .

Görünüşe göre, kullanıyorsanız PropertyConfigurator.configureAndWatch("log4j.properties"), web uygulamanızı çözerken bellek sızıntılarına neden oluyorsunuz.


4

Hazırda + Eclipse RCP bir arada kullanılarak denediniz -XX:MaxPermSize=512mve -XX:PermSize=512mve benim için çalışıyor görünüyor.


4

Ayarlayın -XX:PermSize=64m -XX:MaxPermSize=128m. Daha sonra artmayı da deneyebilirsiniz MaxPermSize. Umarım işe yarar. Aynı şey benim için de geçerli. Ayar sadece MaxPermSizebenim için çalışmadı.


4

Birkaç cevap denedim ve nihayet işi yapan tek şey pom'daki derleyici eklentisi için bu yapılandırma oldu:

<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>

Umarım bu yardımcı olur.


"argLine" maven-compiler-plugin 2.4 tarafından tanınmıyor. yalnızca "compilerArgument" öğesini destekler ve bu hata verir: <compilerArgument> -XX: MaxPermSize = 256m </compilerArgument> [ERROR] Javac yürütme hatası, ancak hatayı ayrıştıramadı: javac: geçersiz bayrak: -XX: MaxPermSize = 256m : javac <seçenekler> <kaynak dosyaları>
Alex

Derleme aşamanızda permen kalıyorsa maven-compiler-plugin üzerinde <compilerArgument> öğesini ayarlayın. Birim testleri, maven-surefire-eklentisinde <argLine> permgen setinin tükenmesi durumunda
qwerty

4

bunu benim için de çözdü; Ancak, sunucu uygulamasının yeniden başlatma sürelerinin çok daha kötü olduğunu fark ettim, bu yüzden üretimde daha iyi olsa da, bir çeşit gelişme oldu.


3

Belleğin yapılandırılması uygulamanızın niteliğine bağlıdır.

Ne yapıyorsun?

Önceden yapılan işlem miktarı nedir?

Ne kadar veri yüklüyorsunuz?

vb.

vb.

vb

Muhtemelen uygulamanızda profil oluşturabilir ve uygulamanızdan bazı modülleri temizlemeye başlayabilirsiniz.

Görünüşe göre bu, bir uygulamayı birkaç kez yeniden konuşlandırdıktan sonra ortaya çıkabilir

Tomcat'in konuşlandırması sıcak ancak belleği tüketiyor. Kapsayı arada bir yeniden başlatmayı deneyin. Ayrıca üretim modunda çalıştırmak için gereken bellek miktarını bilmeniz gerekecek, bu araştırma için iyi bir zaman gibi görünüyor.


3

Tomcat'in son sürümünün (6.0.28 veya 6.0.29), sunucu uygulamalarını yeniden dağıtma görevini çok daha iyi işlediğini söylüyorlar .


3

Aynı problemle karşılaştım, ancak ne yazık ki önerilen çözümlerin hiçbiri gerçekten işe yaramadı. Dağıtım sırasında sorun olmadı ve ben de sıcak dağıtım yapmıyordum.

Benim durumumda, veritabanına (hazırda bekleme yoluyla) bağlanırken, web uygulamamın yürütülmesi sırasında sorun her zaman aynı noktada meydana geldi.

Bu bağlantı (daha önce de belirtilmişti) sorunu çözmek için yeterli bilgiyi sağlamıştır. Jdbc- (mysql) sürücüsünü WEB-INF'den ve jre / lib / ext / klasörüne taşımak sorunu çözmüş görünüyor. Bu, ideal bir çözüm değildir, çünkü daha yeni bir JRE'ye yükseltmek sürücüyü yeniden yüklemenizi gerektirir. Benzer sorunlara neden olabilecek başka bir aday log4j'dir, bu yüzden onu da taşımak isteyebilirsiniz


Sürücüyü jre / lib / ext'e dahil etmek istemiyorsanız, sürücüyü kapsayıcı başlangıç ​​sınıf yolunuza dahil ederek aynı sonuçları alabilirsiniz. java -cp /path/to/jdbc-mysql-driver.jar:/path/to/container/bootstrap.jar konteyner. Başlat
Scot

3

Bu durumda ilk adım GC'nin sınıfları PermGen'den kaldırmasına izin verilip verilmediğini kontrol etmektir. Standart JVM bu konuda oldukça muhafazakardır - sınıflar sonsuza dek yaşamak için doğarlar. Böylece yüklendikten sonra, artık kod kullanmasa bile sınıflar bellekte kalır. Uygulama dinamik olarak çok sayıda sınıf oluşturduğunda ve oluşturulan sınıflar daha uzun süre gerekmediğinde bu bir sorun haline gelebilir. Böyle bir durumda, JVM'nin sınıf tanımlarını boşaltmasına izin vermek yardımcı olabilir. Bu, başlangıç ​​komut dosyalarınıza yalnızca bir yapılandırma parametresi ekleyerek gerçekleştirilebilir:

-XX:+CMSClassUnloadingEnabled

Varsayılan olarak bu false olarak ayarlanmıştır ve bu nedenle etkinleştirmek için Java seçeneklerinde aşağıdaki seçeneği açıkça ayarlamanız gerekir. CMSClassUnloadingEnabled'ı etkinleştirirseniz GC, PermGen'i de süpürecek ve artık kullanılmayan sınıfları kaldıracaktır. Bu seçeneğin yalnızca aşağıdaki seçenek kullanılarak UseConcMarkSweepGC de etkinleştirildiğinde çalışacağını unutmayın. Bu nedenle ParallelGC veya God forbid, Serial GC kullanırken, GC'nizi CMS olarak belirlediğinizden emin olun:

-XX:+UseConcMarkSweepGC

3

Tomcat'e daha fazla bellek atamak doğru çözüm DEĞİLDİR.

Doğru çözüm, içerik yok edildikten ve yeniden oluşturulduktan sonra (sıcak dağıtım) bir temizlik yapmaktır. Çözüm, bellek sızıntılarını durdurmaktır.

Tomcat / Webapp Sunucunuz, sürücülerin (JDBC) kaydını silemediğini söylüyorsa, bunların kaydını silin. Bu, bellek sızıntılarını durduracaktır.

Bir ServletContextListener oluşturabilir ve bunu web.xml dosyasında yapılandırabilirsiniz. İşte örnek bir 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();
        }        
    }
}

Ve burada web.xml dosyasında yapılandırabilirsiniz:

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

2

6.0.29 çalıştırıyorum ve tüm seçenekleri ayarladıktan sonra bile aynı sorun var çünkü "Onlar" yanlış. Tim Howland'ın yukarıda söylediği gibi, bu seçenekler sadece kaçınılmazdır. Her yeniden dağıtım yerine hataya çarpmadan önce 3 kez yeniden konuşlandırmama izin veriyorlar.


2

Eğer eclipse IDE'de bunu alıyorsanız , parametreleri --launcher.XXMaxPermSize, -XX:MaxPermSizevb. Ayarladıktan sonra bile , aynı hatayı alıyorsanız, muhtemelen tutulma JRE'nin bazıları tarafından yüklenmiş olan buggy bir sürümünü kullanıyor olmasıdır. üçüncü taraf uygulamalar ve varsayılan olarak ayarlanmıştır. Bu buggy sürümleri PermSize parametrelerini almaz ve bu nedenle ne ayarlasanız da, bu bellek hatalarını almaya devam edersiniz. Yani, eclipse.ini dosyasına aşağıdaki parametreleri ekleyin:

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

Ayrıca, tutulmada tercihlerde varsayılan JRE'yi doğru java sürümüne ayarladığınızdan emin olun.


2

Benim için çalışmanın tek yolu JRockit JVM ile oldu. MyEclipse 8.6 sürümüne sahibim.

JVM'nin yığını, çalışan bir Java programı tarafından oluşturulan tüm nesneleri depolar. Java, newnesne oluşturmak için işleci kullanır ve yeni nesneler için bellek, çalışma zamanında öbek üzerinde ayrılır. Çöp toplama, artık program tarafından referans verilmeyen nesnelerin içerdiği belleği otomatik olarak boşaltma mekanizmasıdır.


2

Benzer bir sorun yaşıyordum. Benimki JDK 7 + Maven 3.0.2 + Struts 2.0 + Google GUICE bağımlılık enjeksiyon tabanlı bir projedir.

mvn clean packageKomutu çalıştırmayı denediğimde aşağıdaki hatayı gösteriyordu ve "YAPMA HATASI" oluştu

org.apache.maven.surefire.util.SurefireReflectionException: java.lang.reflect.InvocationTargetException; iç içe kural dışı durum java.lang.reflect.InvocationTargetException: null java.lang.reflect.InvocationTargetException Neden: java.lang.OutOfMemoryError: PermGen alanı

Yukarıdaki tüm yararlı ipuçları ve püf noktaları denedim ama ne yazık ki hiçbiri benim için çalıştı. Benim için işe yarayan aşağıdaki adım adım açıklanmaktadır: =>

  1. Pom.xml'nize gidin
  2. Aramak <artifactId>maven-surefire-plugin</artifactId>
  3. Aşağıda gösterildiği gibi yeni bir <configuration>öğe ve ardından <argLine>alt öğe ekleyin -Xmx512m -XX:MaxPermSize=256m=>

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

Umarım yardımcı olur, mutlu programlama :)

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.