Domanda

Recentemente mi sono imbattuto in questo errore nella mia applicazione web:

java.lang.OutOfMemoryError:PermGen spazio

Si tratta di un tipico Hibernate/JPA + IceFaces/JSF applicazione in esecuzione su Tomcat 6 e JDK 1.6.A quanto pare questo può verificarsi dopo ridistribuire l'applicazione un paio di volte.

Quali sono le cause e cosa si può fare per evitare questo?Come posso risolvere il problema?

È stato utile?

Soluzione

La soluzione è stata quella di aggiungere queste bandiere di JVM riga di comando quando Tomcat è iniziato:

-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled

È possibile arrestare il servizio tomcat, poi andando verso il Tomcat/bin e l'esecuzione di tomcat6w.exe.Sotto il "Java" scheda, aggiungere gli argomenti di "Java" Opzioni di dialogo.Fare clic su "OK" e riavviare il servizio.

Se si ottiene un errore il servizio specificato non esiste come servizio installato si consiglia di eseguire:

tomcat6w //ES//servicename

dove servicename è il nome del server come visto in servizi.msc

Fonte:orx commento Eric Agile Risposte.

Altri suggerimenti

È meglio provare -XX:MaxPermSize=128M piuttosto che -XX:MaxPermGen=128M.

Non riesco a capire l'uso preciso di questo pool di memoria, ma ha a che fare con il numero di classi caricato nella JVM.(Permettendo così di classe scarico per tomcat in grado di risolvere il problema). Se le applicazioni genera e compila classi esecuzione è più probabile che hanno bisogno di un pool di memoria più grande di quello di default.

App server PermGen errori che si verificano dopo più distribuzioni sono molto probabilmente causati da riferimenti tenuto dal contenitore nel tuo vecchio apps' classloader.Per esempio, utilizzando un registro personalizzato a livello di classe, a causa di riferimenti che si terrà dal server di applicazione del classloader.È possibile rilevare queste inter-classloader perdite, utilizzando le moderne (la jdk6+) JVM strumenti di analisi come jmap e jhat di guardare quali classi di continuare a svolgersi nella tua app, e la riprogettazione o eliminare il loro uso.Soliti sospetti sono i database, i taglialegna, e altre di base a livello di framework di librerie.

Vedere Classloader perdite:il temuto "java.lang.OutOfMemoryError:PermGen spazio di eccezione" , e soprattutto la sua follow-up post.

Comuni errori che si commettono e pensare che lo spazio heap e permgen spazio stesso, che non è affatto vero.Si potrebbe avere molto spazio rimanente nel mucchio, ma ancora in grado di esaurire la memoria in permgen.

Le cause comuni di OutofMemory in PermGen è ClassLoader.Quando una classe viene caricato nella JVM, tutti i meta dati, insieme con Classloader, è tenuto su PermGen area e saranno di immondizia raccolte quando il Classloader che ha caricato di loro è pronto per la raccolta dei rifiuti.In Caso Classloader ha una perdita di memoria di tutte le classi caricate da resterà nella memoria e causare permGen outofmemory una volta che si ripete un paio di volte.Il classico esempio è Java.lang.OutOfMemoryError:PermGen Spazio in Tomcat.

Ora ci sono due modi per risolvere questo problema:
1.Trovare la causa della Perdita di Memoria o se c'è qualche perdita di memoria.
2.Aumentare le dimensioni del PermGen Spazio utilizzando JVM param -XX:MaxPermSize e -XX:PermSize.

È inoltre possibile controllare 2 Soluzione di Java.lang.OutOfMemoryError in Java per ulteriori dettagli.

Utilizzare il parametro della riga di comando -XX:MaxPermSize=128m per un Sun JVM (ovviamente sostituendo 128 per qualsiasi formato che avete bisogno).

Provare -XX:MaxPermSize=256m e se il problema persiste, provare a -XX:MaxPermSize=512m

Io aggiunto -XX: MaxPermSize = 128m (si può sperimentare che funziona meglio) per VM Argomenti come sto usando l'ide eclipse.Nella maggior parte della JVM, di default PermSize è intorno 64MB che esaurisce la memoria, se ci sono troppe classi o enorme numero di Stringhe nel progetto.

Per eclipse, è anche descritto in risposta.

PASSO 1 :Fare doppio Clic sul server tomcat in Server Scheda

enter image description here

PASSO 2 : Aprire il lancio di Conf e aggiungere -XX: MaxPermSize = 128m alla fine dell'esistente VM argomentazioni.

enter image description here

Ho sbattuto la testa contro questo problema, mentre la distribuzione e annullare la distribuzione di un'applicazione web complessa, troppo, e ho pensato di aggiungere una spiegazione e la mia soluzione.

Quando si distribuisce un'applicazione su Apache Tomcat, un nuovo ClassLoader è creato per app.Il ClassLoader viene quindi utilizzato per caricare tutte le applicazioni di classe e sul undeploy, tutto dovrebbe andare via bene.Tuttavia, in realtà non è proprio così semplice.

Una o più delle classi creati durante l'applicazione web di vita contiene un riferimento statico che, da qualche parte lungo la linea, i riferimenti al ClassLoader.Come riferimento è stato originariamente statico, nessuna quantità di raccolta differenziata e la pulizia di questo riferimento up - il ClassLoader, e tutte le classi è caricato, sono qui per rimanere.

E dopo un paio di impiega, incontriamo la OutOfMemoryError.

Ora, questo è diventato un problema piuttosto serio.Ho potuto verificare che Tomcat è riavviato dopo ogni ridistribuire, ma che prende l'intero server, piuttosto che l'applicazione di essere riassegnati, che spesso non è fattibile.

Così, invece ho messo insieme una soluzione in codice, che funziona su Apache Tomcat 6.0.Non ho provato su altri server di applicazioni, e dobbiamo sottolineare che questo è molto probabile che non funzioni senza alcuna modifica su qualsiasi altro server di applicazioni.

Vorrei anche dire che personalmente odio questo codice, e che nessuno dovrebbe usare questo come un "quick fix" se il codice esistente può essere modificata per utilizzare il corretto spegnimento e metodi di pulizia.L'unica volta che questo dovrebbe essere utilizzato è, se c'è una libreria esterna il codice è dipendente (Nel mio caso, si trattava di un client RADIUS) che non forniscono un mezzo per ripulire i propri riferimenti statici.

Comunque, con il codice.Questo dovrebbe essere chiamato al punto in cui l'applicazione è annullare la distribuzione, come una servlet distruggere o metodo (il metodo migliore) un ServletContextListener del contextDestroyed metodo.

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

In alternativa, è possibile passare alla JRockit cui la gestione permgen diverso, allora il jvm di sun.Generalmente ha prestazioni migliori.

http://www.oracle.com/technetwork/middleware/jrockit/overview/index.html

1) Aumentare la PermGen Dimensione della Memoria

La prima cosa che si può fare è quello di rendere la dimensione della generazione permanente heap spazio più grande.Questo non può essere fatto con il solito –Xms(set iniziale dimensione heap) e –Xmx(set di massima dimensione dell'heap) argomenti JVM, poiché, come accennato, la generazione permanente heap space è completamente separato dal normale Java Heap space e questi argomenti impostare lo spazio per la regolare Java heap space.Tuttavia, ci sono argomenti simili che possono essere utilizzati(almeno con il Sole/OpenJDK jvm) per rendere la dimensione della generazione permanente mucchio più grande:

 -XX:MaxPermSize=128m

Di Default è 64m.

2) Attivare Spazzare

Un altro modo per prendersi cura di questo per bene è quello di consentire alle classi per essere scaricato così il vostro PermGen non si esaurisce mai:

-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled

Roba come che ha lavorato una magia per me in passato.Una cosa, però, c'è un significativo miglioramento delle prestazioni trade off nell'utilizzo di questi, dal momento che permgen spazza farà come un supplemento di 2 richieste per ogni richiesta o qualcosa del genere.È necessario bilanciare l'uso con i compromessi.

È possibile trovare i dettagli di questo errore.

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

Il java.lang.OutOfMemoryError: PermGen spazio messaggio indica che la Generazione Permanente area di memoria è esaurita.

Tutte le applicazioni Java è consentito l'utilizzo di una quantità limitata di memoria.L'esatta quantità di memoria della vostra particolare applicazione può utilizzare è specificato durante l'avvio dell'applicazione.

Java memoria è divisa in regioni diverse che si possono vedere nella seguente immagine:

enter image description here

Metaspace:Un nuovo spazio di memoria è nato

Il JDK 8 HotSpot JVM è ora utilizzando i nativi di memoria per la rappresentazione di metadati di classe e si chiama Metaspace;simile a Oracle JRockit e IBM JVM è.

La buona notizia è che significa che non è più java.lang.OutOfMemoryError: PermGen problemi di spazio e non è necessario per voi per ottimizzare e monitorare spazio di memoria, in più utilizzando Java_8_Download o superiore.

Ho avuto il problema di cui stiamo parlando qui, il mio scenario è eclipse helios + tomcat + jsf e cosa si stava facendo è una distribuzione di una semplice applicazione per tomcat.Ero con lo stesso problema, risolto come segue.

In eclipse andare a server scheda, fare doppio clic sul server registrato nel mio caso tomcat 7.0, si è aperto il mio file server informazioni Generali sulla registrazione.La sezione "Informazioni Generali" clicca sul link "Apri configurazione di lancio" questo apre l'esecuzione del server di opzioni tra gli Argomenti scheda VM argomenti aggiunti in fine a queste due voci

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

e pronto.

La risposta più semplice in questi giorni è quello di utilizzare Java 8.

Non ha più riserve di memoria esclusivamente per PermGen spazio, permettendo la PermGen memoria si mescolano con il normale pool di memoria.

Tenete a mente che si dovrà rimuovere tutti i non-standard -XXPermGen...=... JVM parametri di avvio, se non vuoi Java 8 a lamentarsi che non servono a nulla.

  1. Aprire tomcat7w da Tomcat bin o tipo di Monitor Tomcat nel menu di avvio (schede si apre la finestra con le varie informazioni di servizio).
  2. In Opzioni Java area di testo aggiungere questa riga:

    -XX:MaxPermSize=128m
    
  3. Set Iniziale Pool di Memoria di 1024 (opzionale).
  4. Impostare la quantità Massima di Memoria Piscina a 1024 (opzionale).
  5. Fare Clic Su Ok.
  6. Riavviare il servizio Tomcat.

Perm gen spazio di errore si verifica a causa di uso ampio spazio piuttosto jvm previsto uno spazio per eseguito il codice.La soluzione migliore a questo problema nei sistemi operativi UNIX è quello di cambiare qualche configurazione di bash file.Procedura seguente per risolvere il problema.

Eseguire il comando gedit .bashrc sul terminale.

Creare JAVA_OTPS variabile con il seguente valore:

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

Salvare il file bash.Eseguire il comando exec bash sul terminale.Riavviare il server.

Spero che questo approccio funziona sul vostro problema.Se si utilizza una versione di Java inferiore all ' 8 per questo problema si verifica a volte.Ma se si utilizza Java 8 il problema non si verifica mai.

Crescente Generazione Permanente dimensione o tweaking GC parametri NON aiuterà se si ha una reale perdita di memoria.Se la vostra applicazione o qualche 3rd party libreria utilizzata, perdite di classe loader l'unico reale e permanente soluzione è trovare questo problema e risolverlo.Ci sono un certo numero di strumenti che possono aiutarti, uno degli ultimi è Plumbr, che ha appena pubblicato una nuova versione con le capacità richieste.

Anche se si utilizza log4j nella tua webapp, controllare questo paragrafo in log4j documentazione.

Sembra che se si sta utilizzando PropertyConfigurator.configureAndWatch("log4j.properties"), è causa di perdite di memoria quando si ritira il webapp.

Ho una combinazione di Sospensione+Eclipse RCP, provato con -XX:MaxPermSize=512m e -XX:PermSize=512m e sembra funzionare per me.

Set -XX:PermSize=64m -XX:MaxPermSize=128m.In seguito si può anche provare ad aumentare MaxPermSize.Spero che lavoreremo.Lo stesso funziona per me.Impostazione solo MaxPermSize non ha funzionato per me.

Ho provato varie risposte e l'unica cosa che finalmente ha fatto il lavoro era questa configurazione per il compilatore plugin nel 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>

spero che questo uno aiuta.

risolto questo per me;tuttavia, ho notato che la servlet riavviare i tempi erano molto peggio, mentre così è stato il migliore nella produzione, era una sorta di trascinare in via di sviluppo.

La configurazione della memoria dipende dalla natura dell'applicazione.

Che cosa stai facendo?

Qual è la quantità di transazioni precessed?

La quantità di dati che viene caricata?

ecc.

ecc.

ecc

Probabilmente si potrebbe profilare la tua app e iniziare la pulizia di alcuni moduli dalla tua app.

A quanto pare questo può verificarsi dopo ridistribuire l'applicazione un paio di volte

Tomcat ha hot deploy, ma consuma di memoria.Provare a riavviare il contenitore di tanto in tanto.Inoltre, è necessario conoscere la quantità di memoria necessaria per eseguire in modalità di produzione, questo sembra un buon momento per la ricerca.

Dicono che l'ultima rev di Tomcat (6.0.28 o 6.0.29) gestisce tutte le attività di ridistribuzione di servlet molto meglio.

Ho eseguito esattamente lo stesso problema, ma purtroppo nessuna delle soluzioni proposte davvero lavorato per me.Il problema non è accaduto durante la distribuzione, e io non era né di fare qualsiasi hot distribuzioni.

Nel mio caso il problema si è verificato ogni volta nello stesso punto durante l'esecuzione del mio web-application, mentre il collegamento (tramite hibernate) per il database.

Questo link (anche detto in precedenza) non fornire sufficiente interni per risolvere il problema.Movimento jdbc-(mysql)-driver del WEB-INF e il jre/lib/ext/ cartella sembra aver risolto il problema.Questa non è la soluzione ideale, dal momento che l'aggiornamento a una versione più recente JRE sarebbe necessario reinstallare il driver.Un altro candidato che potrebbe causare problemi simili è log4j, così si potrebbe desiderare di spostare anche quello

Primo passo in tal caso è quello di verificare se il GC è consentito scaricare classi PermGen.La JVM standard è piuttosto conservatore, a questo proposito, le classi sono nato per vivere per sempre.Quindi, una volta caricato, classi di rimanere in memoria anche se nessun codice è il loro utilizzo più.Questo può diventare un problema quando l'applicazione crea un sacco di classi in modo dinamico e le classi generate non sono necessari per periodi più lunghi.In tal caso, consentendo la JVM per scaricare le definizioni di classe può essere utile.Questo può essere ottenuto con l'aggiunta di un solo parametro di configurazione degli script di avvio:

-XX:+CMSClassUnloadingEnabled

Per impostazione predefinita, è impostato su false e così per abilitare questa funzione è necessario impostare esplicitamente la seguente opzione in opzioni Java.Se si attiva CMSClassUnloadingEnabled, GC spazzerà PermGen troppo e rimuovere le classi che non sono più utilizzati.Tenete a mente che questa opzione funziona solo quando UseConcMarkSweepGC è attivata anche utilizzando l'opzione sotto.Così, quando l'esecuzione di ParallelGC o, Dio non voglia, di Serie GC, assicurarsi di aver impostato il vostro GC per CMS, specificando:

-XX:+UseConcMarkSweepGC

Assegnazione di Tomcat più la memoria NON è la soluzione adeguata.

La soluzione corretta è fare una pulizia dopo il contesto è distrutto e ricreato (la distribuzione).La soluzione è quella di fermare le perdite di memoria.

Se il Tomcat/Webapp Server sta dicendo che non è riuscita ad annullare i driver JDBC (), quindi annullare la registrazione di loro.Questo impedisce le perdite di memoria.

È possibile creare un ServletContextListener e configurarlo nel web.xml.Ecco un esempio di 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();
        }        
    }
}

E qui si configura nel vostro web.xml:

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

"Loro" sono sbagliato perché sono in esecuzione 6.0.29 e hanno lo stesso problema anche dopo aver impostato tutte le opzioni.Come Tim Howland detto sopra, queste opzioni solo rimandare l'inevitabile.Mi permettono di ridistribuire 3 volte prima di colpire l'errore invece che ogni volta che ho ridistribuire.

Nel caso In cui si stanno ottenendo questo in IDE eclipse, anche dopo aver impostato i parametri --launcher.XXMaxPermSize, -XX:MaxPermSize, ecc, ancora, se sono sempre lo stesso errore, probabilmente, è che l'eclissi è utilizzando un buggy versione di JRE che sarebbe stato installato da alcune applicazioni di terze parti e impostato al valore di default.Queste versioni difettose non prendere il PermSize parametri e quindi non importa ciò che si imposta, è ancora mantenere sempre questi errori di memoria.Così, in eclipse.ini aggiungere i seguenti parametri:

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

Inoltre, assicurarsi di impostare il valore predefinito JRE nelle preferenze di eclipse per la versione corretta di java.

L'unico modo che ha funzionato per me è stato con il JRockit JVM.Ho MyEclipse 8.6.

La JVM heap di negozi di tutti gli oggetti generati dall'esecuzione di un programma Java.Java utilizza il new operatore di creare oggetti e memoria per i nuovi oggetti è allocata nell'heap in fase di esecuzione.Garbage collection è il meccanismo automatico di liberare la memoria contenute negli oggetti che non fanno più riferimento il programma.

Ho avuto un simile problema.Il mio è JDK 7 + Maven 3.0.2 + Struts 2.0 + Google GUICE dipendenza di iniezione a base di progetto.

Ogni volta che ho provato a correre mvn clean package comando, è stato mostrando il seguente messaggio di errore e "COSTRUIRE IL FALLIMENTO" si è verificato

org.apache.maven.surefire.util.SurefireReflectionException:java.lang.riflettere.InvocationTargetException;nidificato eccezione java.lang.riflettere.InvocationTargetException:null java.lang.riflettere.InvocationTargetException Causato da:java.lang.OutOfMemoryError:PermGen spazio

Ho provato tutto quanto sopra, utili suggerimenti e trucchi, ma purtroppo nessuno ha lavorato per me.Che cosa ha funzionato per me è descritto passo passo qui di seguito :=>

  1. Vai al tuo pom.xml
  2. Ricerca per <artifactId>maven-surefire-plugin</artifactId>
  3. Aggiungere un nuovo <configuration> elemento e quindi <argLine> sub-elemento in cui passare -Xmx512m -XX:MaxPermSize=256m come mostrato di seguito =>

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

Speranza che aiuta, felice di programmazione :)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top