Gestire l'errore "java.lang.OutOfMemoryError: PermGen space"


1222

Di recente ho riscontrato questo errore nella mia applicazione Web:

java.lang.OutOfMemoryError: spazio PermGen

È una tipica applicazione Hibernate / JPA + IceFaces / JSF in esecuzione su Tomcat 6 e JDK 1.6. Apparentemente ciò può accadere dopo aver ridistribuito un'applicazione alcune volte.

Cosa lo causa e cosa si può fare per evitarlo? Come posso risolvere il problema?


Ho combattuto per ore, ma non ho buone notizie. Vedi la mia domanda correlata: stackoverflow.com/questions/1996088/… Potresti avere ancora una perdita di memoria, ad es. Le classi non sono garbage collection perché WebAppClassLoader non è garbage collection (ha un riferimento esterno che non viene cancellato). l'aumento di PermGen ritarderà OutOfMemoryError e consentire la garbage collection di classe è una condizione preliminare, ma non sarà garbage collection delle classi se il loro caricatore di classi ha ancora riferimenti ad esso.
Eran Medan,

Ho riscontrato questo errore durante l'aggiunta di taglib di visualizzazione . La rimozione così risolto anche l'errore. Perchè così?
Mast

E come ci sei riuscito?
Thorbjørn Ravn Andersen,

13
usa JDK 1.8: þ benvenuto nel MetaSpace
Rytek

Se si utilizza Windows, seguire queste istruzioni invece di provare a impostare manualmente i flag nei file di configurazione. Ciò imposta correttamente i valori nel registro che saranno chiamati da Tomcat durante il runtime. stackoverflow.com/questions/21104340/…
MacGyver

Risposte:


563

La soluzione era aggiungere questi flag alla riga di comando JVM all'avvio di Tomcat:

-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled

Puoi farlo arrestando il servizio Tomcat, quindi accedendo alla directory Tomcat / bin ed eseguendo tomcat6w.exe. Nella scheda "Java", aggiungi gli argomenti alla casella "Opzioni Java". Fai clic su "OK", quindi riavvia il servizio.

Se viene visualizzato un errore, il servizio specificato non esiste come servizio installato, è necessario eseguire:

tomcat6w //ES//servicename

dove servicename è il nome del server visualizzato in services.msc

Fonte: commento di orx sulle risposte agili di Eric .


39
L'articolo che segue suggerisce -XX: + UseConcMarkSweepGC e -XX: MaxPermSize = 128m pure. my.opera.com/karmazilla/blog/2007/03/13/…
Taylor Leese,

30
-XX: + CMSPermGenSweepingEnabled Questa opzione riduce le prestazioni. Ogni richiesta richiede tre volte più tempo del solito sui nostri sistemi. Usare con cura.
Eldelshell,

10
ha funzionato per me - grazie - Lo sto facendo su Ubuntu 10.10 con Tomcat6 - Ho creato un nuovo file: /usr/share/tomcat6/bin/setenv.sh e ho aggiunto la seguente riga a quella: JAVA_OPTS = "- Xms256m -Xmx512m - XX: + CMSClassUnloadingEnabled -XX: + CMSPermGenSweepingEnabled "- Tomcat riavviato utilizzando: sudo /etc/init.d/tomcat6 start
sami

24
All'avvio di Tomcat 6.0.29, dal mio file di log catalina.out: "Utilizzare CMSClassUnloadingEnabled al posto di CMSPermGenSweepingEnabled in futuro"
anno

222
Prima di tutto sarebbe bello spiegare cosa fanno davvero queste bandiere. Solo dire: "fallo e divertiti" non è abbastanza IMHO.
Nikem,

251

Faresti meglio a provare -XX:MaxPermSize=128Mpiuttosto che -XX:MaxPermGen=128M.

Non posso dire l'uso preciso di questo pool di memoria, ma ha a che fare con il numero di classi caricate nella JVM. (Pertanto, abilitare lo scaricamento di classi per tomcat può risolvere il problema.) Se le applicazioni generano e compilano classi in esecuzione, è più probabile che sia necessario un pool di memoria più grande del valore predefinito.


9
In realtà, questo rimanderà solo OOMError. Vedi la risposta sotto iniziata da anon con due link al blog di frankkieviet.
Rade_303,

Queste opzioni sono spiegate qui: oracle.com/technetwork/java/javase/tech/…
amos,

153

Gli errori PermGen del server app che si verificano dopo più distribuzioni sono molto probabilmente causati da riferimenti conservati dal contenitore nei programmi di caricamento classi delle vecchie app. Ad esempio, l'utilizzo di una classe di livello di registro personalizzata comporterà la conservazione dei riferimenti da parte del classloader del server delle app. Puoi rilevare queste perdite tra i classloader utilizzando i moderni strumenti di analisi JVM (JDK6 +) come jmap e jhat per vedere quali classi continuano a essere tenute nella tua app e riprogettandone o eliminandone l'uso. I soliti sospetti sono database, logger e altre librerie a livello di framework di base.

Vedi le perdite di Classloader: la temuta eccezione "java.lang.OutOfMemoryError: PermGen space" , e in particolare il suo post di follow-up .


3
Questa è solo una vera soluzione al problema, in alcuni casi troppo difficile da implementare.
Rade_303,

Un'altra ottima fonte è people.apache.org/~markt/presentations/… (dal gestore delle versioni di Tomcat !!).
gavenkoa,

22
Sebbene ciò possa teoricamente rispondere alla domanda, sarebbe preferibile includere qui le parti essenziali della risposta e fornire il collegamento come riferimento.
Joachim Sauer,

68

Gli errori comuni che la gente fa è pensare che lo spazio heap e lo spazio permgen siano uguali, il che non è affatto vero. Potresti avere molto spazio rimanente nell'heap ma puoi ancora esaurire la memoria in permgen.

Cause comuni di OutofMemory in PermGen è ClassLoader. Ogni volta che una classe viene caricata in JVM, tutti i suoi metadati, insieme a Classloader, vengono mantenuti nell'area di PermGen e verranno raccolti in modo inutile quando Classloader che li ha caricati è pronto per la garbage collection. In Case Classloader ha una perdita di memoria rispetto a tutte le classi caricate da essa rimarrà in memoria e causerà la perdita di memoria di PermGen una volta ripetuta un paio di volte. L'esempio classico è Java.lang.OutOfMemoryError: PermGen Space in Tomcat .

Ora ci sono due modi per risolverlo:
1. Trova la causa della perdita di memoria o se c'è qualche perdita di memoria.
2. Aumentare le dimensioni di PermGen Space usando JVM param -XX:MaxPermSizee -XX:PermSize.

Puoi anche controllare 2 Solution of Java.lang.OutOfMemoryError in Java per maggiori dettagli.


3
Come passare param -XX:MaxPermSize and -XX:PermSize?? Non riesco a trovare catalina.bat. La mia versione di Tomcat è 5.5.26.
Deckard

Come trovare le perdite di memoria del caricatore di classi? Mi consigliate qualche strumento?
Entro il

@amit per consigli sugli strumenti, vedere la risposta wiki della community su questa domanda.
Barett,

@Deckard accede alla directory Tomcat / bin ed esegue tomcat6w.exe. Nella scheda "Java", aggiungi gli argomenti alla casella "Opzioni Java". Fai clic su "OK"
Zeb

43

Utilizzare il parametro della riga di comando -XX:MaxPermSize=128mper un Sun JVM (sostituendo ovviamente 128 per qualsiasi dimensione sia necessaria).


9
L'unico problema è che stai solo ritardando l'inevitabile, a un certo punto finirai anche per avere un margine di manovra. È un'ottima soluzione pragmatica, ma non la risolve in modo permanente.
Tim Howland,

la stessa cosa accade in Eclipse e ogni volta che hai un sacco di caricamento dinamico della classe. i classloader non vengono eliminati e vivono nella generazione permanente per l'eternità
Matt,

1
Stavo finendo PermGen quando eseguivo un lavoro Hudson particolarmente grande ... questo mi ha risolto.
HDave

10
@TimHowland, può essere una correzione permanente se la causa principale non è la perdita del classloader, solo troppe classi / dati statici nella tua app web.
Péter Török,

ha lo stesso problema di HDave quando si costruisce jenkins / hudson dalla fonte.
louisgab,

38

Prova -XX:MaxPermSize=256me se persiste, prova-XX:MaxPermSize=512m


56
e se persiste, prova XX:MaxPermSize=1024m:)
igo

38
e se persiste, prova XX: MaxPermSize = 2048m :)
Thomas

16
E se ANCORA persiste, ripensa alla tua applicazione !! Oppure prova XX: MaxPermSize = 4096m :)
Jonathan Airey,

17
puoi anche provare 8192 m, ma è un po 'eccessivo
Jacek Pietal,

12
Overkill davvero - 640 KB dovrebbe essere sufficiente per chiunque!
Joel Purra,

28

Ho aggiunto -XX: MaxPermSize = 128m (puoi sperimentare quale funziona meglio) agli argomenti di VM mentre sto usando l'eclissi ide. Nella maggior parte di JVM, PermSize predefinito è di circa 64 MB che esaurisce la memoria se ci sono troppe classi o un numero enorme di stringhe nel progetto.

Per l'eclissi, è anche descritto alla risposta .

PASSAGGIO 1 : fare doppio clic sul server Tomcat nella scheda Server

inserisci qui la descrizione dell'immagine

PASSAGGIO 2 : aprire Config di avvio e aggiungere -XX: MaxPermSize = 128malla fine degli argomenti VM esistenti .

inserisci qui la descrizione dell'immagine


1
Grazie per la migliore risposta dettagliata (Nota: fare clic su "Apri configurazione di avvio" per aprire la finestra "modifica configurazione" ... ma ho usato i seguenti parametri: "-XX: + CMSClassUnloadingEnabled -XX: + CMSPermGenSweepingEnabled"
Chris Sim

23

Mi sono opposto a questo problema durante la distribuzione e la distribuzione di un'applicazione Web complessa, e ho pensato di aggiungere una spiegazione e la mia soluzione.

Quando distribuisco un'applicazione su Apache Tomcat, viene creato un nuovo ClassLoader per quell'app. ClassLoader viene quindi utilizzato per caricare tutte le classi dell'applicazione e su undeploy, tutto dovrebbe andare bene. Tuttavia, in realtà non è così semplice.

Una o più delle classi create durante la vita dell'applicazione Web contengono un riferimento statico che, da qualche parte lungo la linea, fa riferimento a ClassLoader. Dato che il riferimento è originariamente statico, nessuna quantità di garbage collection ripulirà questo riferimento: ClassLoader e tutte le classi caricate, restano qui per rimanere.

E dopo un paio di redeploys, incontriamo OutOfMemoryError.

Ora questo è diventato un problema abbastanza serio. Potrei assicurarmi che Tomcat venga riavviato dopo ogni ridistribuzione, ma che rimuove l'intero server, anziché solo l'applicazione da ridistribuire, il che spesso non è fattibile.

Quindi invece ho messo insieme una soluzione in codice, che funziona su Apache Tomcat 6.0. Non ho testato su nessun altro server applicazioni e devo sottolineare che molto probabilmente non funzionerà senza modifiche su nessun altro server applicazioni .

Vorrei anche dire che personalmente odio questo codice e che nessuno dovrebbe usarlo come "soluzione rapida" se il codice esistente può essere modificato per utilizzare i metodi di spegnimento e pulizia corretti . L'unica volta che questo dovrebbe essere usato è se c'è una libreria esterna da cui dipende il tuo codice (Nel mio caso, era un client RADIUS) che non fornisce un mezzo per ripulire i propri riferimenti statici.

Comunque, con il codice. Questo dovrebbe essere chiamato nel punto in cui l'applicazione non è dispiegata, come il metodo di distruzione di un servlet o (l'approccio migliore) il metodo di Contesto distrutto di 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();

So che sono passati più di 8 anni da quando ho scritto questo, ma da qualche parte tra allora e ora ho trovato una causa e una soluzione di radice più profonde. Ciò è accaduto che mentre tutte le classi all'interno della webapp sono di proprietà del caricatore di classi di contesto, il thread che richiama il callback di avvio e arresto è di proprietà del caricatore di classi padre. Ciò significa che se il codice di arresto inizializza una variabile thread-local, ciò causerà il caricamento del classloader padre in possesso di un riferimento al caricatore di contesto contestuale, impedendo una buona pulizia.
Edward Torbett,

Fortunatamente, esiste una soluzione molto semplice: sposta tutto il codice attualmente nel metodo di arresto nel metodo di esecuzione di un nuovo oggetto Thread. Quindi nel metodo di arresto, avvia questo thread e attendi il completamento. Il codice di cleanup verrà eseguito in modo identico, ma qualsiasi variabile thread-local rimarrà legata al classloader di contesto invece di perdere.
Edward Torbett,

20

Il java.lang.OutOfMemoryError: PermGenmessaggio spaziale indica che l'area della generazione permanente in memoria è esaurita.

A qualsiasi applicazione Java è consentito utilizzare una quantità limitata di memoria. La quantità esatta di memoria che può essere utilizzata dall'applicazione specifica viene specificata all'avvio dell'applicazione.

La memoria Java è separata in diverse regioni che possono essere viste nella seguente immagine:

inserisci qui la descrizione dell'immagine

Metaspace: nasce un nuovo spazio di memoria

JDK 8 HotSpot JVM ora utilizza la memoria nativa per la rappresentazione di metadati di classe e si chiama Metaspace; simile a Oracle JRockit e IBM JVM.

La buona notizia è che non significa più java.lang.OutOfMemoryError: PermGenproblemi di spazio e non è più necessario ottimizzare e monitorare questo spazio di memoria utilizzando Java_8_Download o versione successiva.


17

1) Aumentare la dimensione della memoria PermGen

La prima cosa che si può fare è aumentare le dimensioni dello spazio di heap di generazione permanente. Questo non può essere fatto con i soliti argomenti JVM –Xms (imposta la dimensione iniziale dell'heap) e –Xmx (imposta la dimensione massima dell'heap), poiché, come detto, lo spazio heap di generazione permanente è completamente separato dal normale spazio Heap Java e questi argomenti impostati lo spazio per questo normale spazio heap Java. Tuttavia, esistono argomenti simili che possono essere utilizzati (almeno con i jvms Sun / OpenJDK) per aumentare le dimensioni dell'heap di generazione permanente:

 -XX:MaxPermSize=128m

L'impostazione predefinita è 64 m.

2) Abilita Spazzare

Un altro modo per occuparsene per sempre è consentire alle classi di essere scaricate in modo che il tuo PermGen non si esaurisca mai:

-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled

Roba del genere ha funzionato magicamente per me in passato. Una cosa però, c'è un notevole compromesso prestazionale nell'utilizzarli, poiché gli swift di permgen faranno come ulteriori 2 richieste per ogni richiesta che fai o qualcosa del genere. Dovrai bilanciare il tuo utilizzo con i compromessi.

Puoi trovare i dettagli di questo errore.

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


Ottimo post di @faisalbhagat faisalbhagat.blogspot.com/2014/09/…
leomeurer

L'opzione 2 è eccezionale, ma tieni presente che non deve essere utilizzato negli ambienti di produzione. In genere è meglio conservarlo solo negli ambienti di sviluppo. Tuttavia PermGen viene rimosso da Java 8 openjdk.java.net/jeps/122
hdost


14

Ho avuto il problema di cui stiamo parlando qui, il mio scenario è eclipse-helios + tomcat + jsf e quello che stavi facendo è stato realizzare una semplice applicazione su tomcat. Stavo mostrando lo stesso problema qui, risolto come segue.

In eclipse vai alla scheda server fare doppio clic sul server registrato nel mio caso Tomcat 7.0, apre il mio file server Informazioni di registrazione generali. Nella sezione "Informazioni generali" fare clic sul collegamento "Apri configurazione di avvio" , questo apre l'esecuzione delle opzioni del server nella scheda Argomenti negli argomenti VM aggiunti alla fine queste due voci

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

e pronto.


14

La risposta più semplice in questi giorni è usare Java 8.

Non riserva più memoria esclusivamente per lo spazio PermGen, consentendo alla memoria PermGen di mescolarsi con il normale pool di memoria.

Tieni presente che dovrai rimuovere tutti -XXPermGen...=...i parametri di avvio JVM non standard se non vuoi che Java 8 si lamenti del fatto che non fanno nulla.


Ciao, questa risposta è già stata data: stackoverflow.com/a/22897121/505893 . Per favore cancella la tua risposta, per chiarezza. Se necessario, potresti migliorare la risposta che ho citato. Grazie;)
bluastro

6
@bluish Grazie per averlo sottolineato; tuttavia, questa risposta va di pari passo parlando di OutOfMemoryExceptions e di perdite di metadati. Inoltre, non menziona i punti molto importanti della rimozione dell'opzione PermGen. In breve, non sono sicuro che migliorerei la risposta, ma piuttosto riscriverla. Se fosse solo un rapido ritocco, mi sentirei meno titubante, ma sembra che sarebbe molto più di un semplice ritocco e odio offendere l'autore originale. Tuttavia, questa lista di risposte è la cena di un pasticcio per cani, e forse uccidere il mio post sarebbe comunque meglio.
Edwin Buck,

8
  1. Apri tomcat7w dalla directory bin di Tomcat o digita Monitor Tomcat nel menu di avvio (si apre una finestra a schede con varie informazioni di servizio).
  2. Nell'area di testo Opzioni Java aggiungi questa riga:

    -XX:MaxPermSize=128m
  3. Impostare Initial Memory Pool su 1024 (opzionale).
  4. Impostare Maximum Memory Pool su 1024 (opzionale).
  5. Fai clic su OK.
  6. Riavvia il servizio Tomcat.

6

Si verifica un errore nello spazio di generazione a causa dell'uso di spazio ampio anziché di jvm fornito spazio per eseguire il codice.

La migliore soluzione per questo problema nei sistemi operativi UNIX è modificare alcune configurazioni nel file bash. I seguenti passaggi risolvono il problema.

Esegui comando gedit .bashrcsul terminale.

Creare una JAVA_OTPSvariabile con il seguente valore:

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

Salva il file bash. Eseguire il comando exec bash sul terminale. Riavvia il server.

Spero che questo approccio funzioni sul tuo problema. Se si utilizza una versione Java precedente alla 8 questo problema si verifica a volte. Ma se si utilizza Java 8 il problema non si verifica mai.


5

L'aumento della dimensione della generazione permanente o l'ottimizzazione dei parametri GC NON sono di aiuto se si dispone di una vera perdita di memoria. Se l'applicazione o una libreria di terze parti che utilizza, i caricatori di classi di perdite, l'unica soluzione reale e permanente è quella di trovare questa perdita e risolverla. Esistono numerosi strumenti che possono aiutarti, uno dei più recenti è Plumbr , che ha appena rilasciato una nuova versione con le funzionalità richieste.


5

Inoltre, se stai usando log4j nella tua webapp, controlla questo paragrafo nella documentazione di log4j .

Sembra che se si sta utilizzando PropertyConfigurator.configureAndWatch("log4j.properties"), si causano perdite di memoria quando si annulla la distribuzione della webapp.


4

Ho una combinazione di Hibernate + Eclipse RCP, ho provato a usare -XX:MaxPermSize=512me -XX:PermSize=512me sembra funzionare per me.


4

Set -XX:PermSize=64m -XX:MaxPermSize=128m. In seguito potresti anche provare ad aumentare MaxPermSize. Spero che funzioni. Lo stesso funziona per me. L'impostazione MaxPermSizenon ha funzionato solo per me.


4

Ho provato diverse risposte e l'unica cosa che alla fine ha fatto il lavoro è stata questa configurazione per il plugin del compilatore 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 aiuti.


"argLine" non è riconosciuto da maven-compiler-plugin 2.4. supporta solo "compilerArgument", che fornisce l'errore: <compilerArgument> -XX: MaxPermSize = 256m </compilerArgument> [ERRORE] Errore durante l'esecuzione di javac, ma impossibile analizzare l'errore: javac: flag non valido: -XX: MaxPermSize = 256m Utilizzo : javac <opzioni> <file sorgente>
Alex

Se la tua fase di compilazione si sta esaurendo permgen imposta <compilerArgument> sul plugin-compilatore-maven. Se i test unitari si stanno esaurendo permgen, impostare <argLine> nel plug-in maven-surefire
qwerty,

4

risolto anche questo per me; tuttavia, ho notato che i tempi di riavvio del servlet erano molto peggiori, quindi mentre era migliore in produzione, era un po 'un freno allo sviluppo.


3

La configurazione della memoria dipende dalla natura della tua app.

Cosa fai?

Qual è la quantità di transazioni necessarie?

Quanti dati stai caricando?

eccetera.

eccetera.

eccetera

Probabilmente potresti profilare la tua app e iniziare a ripulire alcuni moduli dalla tua app.

Apparentemente ciò può accadere dopo aver ridistribuito un'applicazione alcune volte

Tomcat ha una distribuzione a caldo ma consuma memoria. Prova a riavviare il contenitore di tanto in tanto. Inoltre dovrai conoscere la quantità di memoria necessaria per funzionare in modalità di produzione, questo sembra un buon momento per quella ricerca.


3

Dicono che l'ultimo rev di Tomcat (6.0.28 o 6.0.29) gestisca il compito di ridistribuire servlet molto meglio.


3

Ho riscontrato esattamente lo stesso problema, ma sfortunatamente nessuna delle soluzioni suggerite ha funzionato davvero per me. Il problema non si è verificato durante la distribuzione e non stavo eseguendo alcuna distribuzione a caldo.

Nel mio caso il problema si è verificato ogni volta nello stesso punto durante l'esecuzione della mia applicazione web, mentre mi collegavo (via ibernazione) al database.

Questo link (anche menzionato in precedenza) forniva abbastanza interni per risolvere il problema. Spostare il driver jdbc- (mysql) fuori dal WEB-INF e nella cartella jre / lib / ext / sembra aver risolto il problema. Questa non è la soluzione ideale, poiché l'aggiornamento a un JRE più recente richiederebbe la reinstallazione del driver. Un altro candidato che potrebbe causare problemi simili è log4j, quindi potresti voler spostare anche quello


Se non si desidera includere il driver in jre / lib / ext, è possibile che si ottengano gli stessi risultati includendo il driver nel percorso di classe di avvio del contenitore. java -cp /path/to/jdbc-mysql-driver.jar:/path/to/container/bootstrap.jar container.Start
Scot,

3

Il primo passo in tal caso è verificare se al GC è consentito scaricare classi da PermGen. La JVM standard è piuttosto conservatrice in questo senso: le classi nascono per vivere per sempre. Quindi, una volta caricate, le classi rimangono in memoria anche se nessun codice le utilizza più. Questo può diventare un problema quando l'applicazione crea molte classi in modo dinamico e le classi generate non sono necessarie per periodi più lunghi. In tal caso, può essere utile consentire alla JVM di scaricare le definizioni di classe. Ciò può essere ottenuto aggiungendo un solo parametro di configurazione agli script di avvio:

-XX:+CMSClassUnloadingEnabled

Per impostazione predefinita, questo è impostato su false e quindi per abilitarlo è necessario impostare esplicitamente la seguente opzione nelle opzioni Java. Se abiliti CMSClassUnloadingEnabled, GC spazzerà anche PermGen e rimuoverà le classi che non vengono più utilizzate. Tieni presente che questa opzione funziona solo quando UseConcMarkSweepGC è abilitato anche utilizzando l'opzione seguente. Pertanto, quando si esegue ParallelGC o, Dio non voglia, GC seriale, assicurarsi di aver impostato il GC su CMS specificando:

-XX:+UseConcMarkSweepGC

3

Assegnare a Tomcat più memoria NON è la soluzione corretta.

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

Se il tuo server Tomcat / Webapp ti sta dicendo che non è stato possibile annullare la registrazione dei driver (JDBC), annullarli. Questo fermerà le perdite di memoria.

Puoi creare un ServletContextListener e configurarlo nel tuo 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 lo configura nel tuo web.xml:

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

2

"Loro" sono sbagliati perché sto eseguendo 6.0.29 e hanno lo stesso problema anche dopo aver impostato tutte le opzioni. Come ha detto Tim Howland sopra, queste opzioni rimandano solo l'inevitabile. Mi permettono di ridistribuire 3 volte prima di colpire l'errore anziché ogni volta che ridistribuisco.


2

Nel caso in cui si ottenga questo nell'IDE di eclissi, anche dopo aver impostato i parametri --launcher.XXMaxPermSize, -XX:MaxPermSizeecc., Anche se si riscontra lo stesso errore, è molto probabile che l'eclissi stia utilizzando una versione buggy di JRE che sarebbe stata installata da alcuni applicazioni di terze parti e impostazione predefinita. Queste versioni buggy non raccolgono i parametri PermSize e quindi, indipendentemente da ciò che imposti, continui comunque a ricevere questi errori di memoria. Quindi, nel tuo eclipse.ini aggiungi i seguenti parametri:

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

Assicurati anche di impostare il JRE predefinito nelle preferenze nell'eclissi sulla versione corretta di java.


2

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

L'heap di JVM memorizza tutti gli oggetti generati da un programma Java in esecuzione. Java utilizza l' newoperatore per creare oggetti e la memoria per i nuovi oggetti viene allocata sull'heap in fase di esecuzione. La garbage collection è il meccanismo per liberare automaticamente la memoria contenuta dagli oggetti a cui non fa più riferimento il programma.


2

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

Ogni volta che ho provato in esecuzione mvn clean packagedi comando, stava mostrando seguente errore e "BUILD GUASTO" si è verificato

org.apache.maven.surefire.util.SurefireReflectionException: java.lang.reflect.InvocationTargetException; l'eccezione nidificata è java.lang.reflect.InvocationTargetException: null java.lang.reflect.InvocationTargetException Causato da: java.lang.OutOfMemoryError: PermGen space

Ho provato tutti i trucchi e suggerimenti utili sopra, ma purtroppo nessuno ha funzionato per me. Quello che ha funzionato per me è descritto passo dopo passo sotto: =>

  1. Vai al tuo pom.xml
  2. Cercare <artifactId>maven-surefire-plugin</artifactId>
  3. Aggiungi un nuovo <configuration>elemento e quindi l' <argLine>elemento secondario in cui passa-Xmx512m -XX:MaxPermSize=256m come mostrato di seguito =>

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

Spero che sia d'aiuto, buona programmazione :)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.