2009-09-20 14 views
41

Sto sviluppando sulla piattaforma di sollevamento standard (maven e jetty). Sono più volte (una volta ogni due giorni) ottenere questo:Problemi PermGen con Lift e Jetty

Exception in thread "[email protected]" java.lang.OutOfMemoryError: PermGen space 
2009-09-15 19:41:38.629::WARN: handle failed 
java.lang.OutOfMemoryError: PermGen space 

Questo è a mio ambiente dev. Non è un problema perché posso continuare a riavviare il server. Nella distribuzione non ho questi problemi quindi non è un problema reale. Sono solo curioso.

Non conosco troppo la JVM. Penso di essere nel giusto pensando che la memoria della generazione permanente sia per cose come le classi e le stringhe interne? Quello che ricordo è un po 'confuso con il modello di memoria .NET ...

Qualsiasi motivo per cui questo sta accadendo? Le impostazioni predefinite sono appena follemente basse? Ha a che fare con tutti gli oggetti ausiliari che Scala deve creare per oggetti Function e cose simili su FP? Ogni volta che riavvio Jetty con il codice appena scritto (ogni pochi minuti) immagino che ri-carica le classi ecc. Ma anche così, non può essere che molti possono? E la JVM non dovrebbe essere in grado di gestire un gran numero di classi?

Acclamazioni

Joe

+1

Come menzionato nel https://web.archive.org/web/20150105090518/http://www.scala-blogs.org/2007/12/scala-statically-typed-dynamic-language. Articolo html: "Il garbage collector generazionale di JVM è ottimizzato per situazioni come questa e poiché gli oggetti creati in modo implicito sono di breve durata, avranno GC molto bene.". ma se quegli oggetti non sono di breve durata, questa è un'altra storia. – VonC

risposta

44

Da this post:

Questa eccezione si è verificato per una semplice ragione:
il permgenspace è dove le proprietà di classe, come metodi, campi, annotazioni e anche variabili statiche, ecc, sono memorizzati in la Java VM, ma questo spazio ha la particolarità di non essere pulito dal garbage collector. Quindi se la tua webapp utilizza o crea un sacco di classi (sto pensando a generazioni dinamiche di classi), è probabile che hai incontrato questo problema. Ecco alcune soluzioni che mi hanno aiutato sbarazzarsi di questa eccezione:

  • -XX:+CMSClassUnloadingEnabled: Questa impostazione consente la raccolta dei rifiuti nel permgenspace
  • -XX:+CMSPermGenSweepingEnabled: permette il garbage collector per rimuovere anche le classi dalla memoria
  • -XX:PermSize=64M -XX:MaxPermSize=128M: aumenta la quantità di memoria allocata al permgenspace

Potrebbe essere utile.

Modifica luglio 2012 (quasi 3 anni più tardi):

Ondra Žižka commenti (e ho aggiornato la risposta di cui sopra):

JVM 1.6.0_27 dice: Si prega di utilizzare:

  • CMSClassUnloadingEnabled (Se lo svuotamento di classe è abilitato quando si utilizza CMS GC)
  • in sostituzione di CMSPermGenSweepingEnabled in futuro

Vedere l'intero Hotspot JVM Options - The complete reference per mroe.

+1

Grazie. Ho pensato che sia la regolazione del comportamento del GC sia la dimensione di PermGen avrebbe risolto il problema.Sto davvero cercando una ragione specifica per cui (/ se) Lift muoverebbe gli oggetti PermGen. – Joe

+1

Può essere a causa di alcune generazioni di classi dinamiche eseguite da Lift. – VonC

+3

JVM 1.6.0_27 dice: Si prega di utilizzare 'CMSClassUnloadingEnabled' al posto di' CMSPermGenSweepingEnabled' in futuro. –

1

La generazione permanente è dove la JVM mette cose che non sarà probabilmente (spazzatura) raccolti come classloader personalizzati.

A seconda di ciò che si sta distribuendo, l'impostazione del gen di perm può essere bassa. Alcune combinazioni di applicazioni e/o contenitori contengono alcune perdite di memoria, quindi quando un'app viene annullata, a volte alcuni elementi come i programmi di caricamento delle classi non vengono raccolti, con conseguente riempimento dello Spazio Perm così da generare l'errore che si sta verificando.

Purtroppo, attualmente la migliore opzione in questo caso è al massimo lo spazio permanente con il seguente bandierina JVM (ad esempio per le dimensioni 192m perm):

-XX:MaxPermSize=192M (or 256M) 

L'altra opzione è quella di fare in modo che sia il contenitore o il framework non perdono memoria.

+0

Deve esserci un '=' tra MaxPermSize e 192m. –

2

La mailing list (http://groups.google.com/group/liftweb/) è il forum di supporto ufficiale per Lift e in cui è possibile ottenere una risposta migliore. Non conosco i dettagli del tuo setup di sviluppo (non vai nei dettagli), ma presumo che tu stia ricaricando la tua guerra in Jetty senza ricominciare. Lift non esegue la generazione di classi dinamiche (come suggerito da VonC sopra), ma Scala compila ogni chiusura come una classe separata. Se stai aggiungendo e rimuovendo chiusure al tuo codice nel corso di diversi giorni, è possibile che troppe classi vengano caricate e mai scaricate e occupando spazio di perm. Ti suggerirei di abilitare le opzioni opzioni JVM menzionate da VonC sopra e vedere se aiutano.

+1

Grazie. Di solito pubblico un post sul gruppo Google, ma ho pensato di dare a StackOverflow un via. Cercherò di aumentare i numeri. – Joe

3

Ciò è dovuto al ricaricamento delle classi come suggerito. Se si utilizzano molte librerie ecc. La somma delle classi crescerà rapidamente per ogni riavvio. Prova a monitorare la tua istanza di jetty con VisualVM per ottenere una panoramica del consumo di memoria durante il ricaricamento.

12

Se si vede questo quando si esegue mvn jetty:run, impostare MAVEN_OPTS.

Per Linux:

export MAVEN_OPTS="-XX:+CMSClassUnloadingEnabled -XX:PermSize=256M -XX:MaxPermSize=512M" 
mvn jetty:run 

Per Windows:

set "MAVEN_OPTS=-XX:+CMSClassUnloadingEnabled -XX:PermSize=256M -XX:MaxPermSize=512M" 
mvn jetty:run 

dovrebbe andare bene ora. In caso contrario, aumentare -XX:MaxPermSize.

È inoltre possibile inserirli in modo permanente nel proprio ambiente.