2010-07-26 6 views
168

Non riesco a trovare la definizione di ciò che il flag Java VM CMSClassUnloadingEnabled effettivamente fa, a parte alcune definizioni di alto livello molto sfocate come "elimina i problemi PermGen" (which it doesn't, btw).Cosa JVM bandiera CMSClassUnloadingEnabled effettivamente fare?

ho guardato/sito di Oracle di Sun, e anche the options list in realtà non dire quello che fa.

Sulla base del nome della bandiera, suppongo che CMS Garbage Collector non scarichi automaticamente le classi e questo flag lo attivi, ma non posso esserne sicuro.

risposta

201

Aggiornamento Questa risposta è rilevante per Java 5-7, Java 8 ha fissato questo: https://blogs.oracle.com/poonam/about-g1-garbage-collector,-permanent-generation-and-metaspace Complimenti vanno a mt.uulu

Per Java 5-7:

Lo standard di Oracle/Sun VM guardare il mondo è: le classi sono per sempre. Quindi una volta caricati, rimangono in memoria anche se a nessuno importa più. Questo di solito non è un problema dal momento che non avete che molte classi puramente "Setup" (= usati una volta per la configurazione e poi mai più). Quindi anche se occupano 1 MB, a chi importa.

Ma ultimamente, abbiamo linguaggi come Groovy, che definiscono le classi in fase di esecuzione. Ogni volta che esegui uno script, vengono create una (o più) nuove classi e rimangono permanentemente in PermGen. Se stai usando un server, significa che hai una perdita di memoria.

Se si attiva CMSClassUnloadingEnabled, il GC spazzerà anche PermGen e rimuoverà le classi che non vengono più utilizzate.

[EDIT] Avrete anche per consentire UseConcMarkSweepGC (grazie a Sam Hasler). Vedere questa risposta: https://stackoverflow.com/a/3720052/2541

+15

Secondo http://stackoverflow.com/a/3720052/2541 per 'CMSClassUnloadingEnabled' di avere qualsiasi impatto, 'UseConcMarkSweepGC' deve essere impostato anche –

+1

Non so come questo influisce sull'uso di UseConcatSweepGC, ma sembra che ci sia stato un bug recentemente corretto in CMSClassUnloadingEnabled. Viene osservato come corretto qui: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=8000325 – BillR

+0

Per le lingue come Groovy che definiscono dinamicamente le classi, è buona norma abilitare questo flag per pulire periodicamente PermGen? –

34

In base al post del blog The most complete list of -XX options for Java JVM, determina se il garbage collector CMS abilita lo scaricamento della classe. L'impostazione predefinita è false. V'è un'altra opzione chiamata ClassUnloading che è true di default, (presumibilmente) influisce sulle altre netturbini.

L'idea è che se il GC rileva che una classe precedentemente caricata non è più utilizzata da nessuna parte nella JVM, può recuperare la memoria utilizzata per contenere il codice bytecode e/o nativo delle classi.

Impostazione CMSClassUnloadingEnabled potrebbe aiuto con il tuo problema PermGen se si sta utilizzando il collettore CMS. Tuttavia, è probabile che tu non stia utilizzando il CMS o che tu abbia una vera perdita di memoria relativa al classloader. In quest'ultimo caso, la tua classe non apparirà mai al GC da non usare ... e quindi non verrà mai scaricata.


Aaron Digulla dice "le classi sono per sempre". Questo non è assolutamente vero, anche nel mondo puramente Java. In effetti, la durata di una classe è legata al suo classloader. Quindi, se puoi organizzare che un programma di caricamento di classi venga raccolto in modo automatico (e questa non è sempre una cosa facile da fare), anche le classi caricate saranno raccolte automaticamente.

In realtà, questo è ciò che accade quando si esegue una redeploy caldo di una webapp. (O almeno, questo è ciò che dovrebbe accadere, se è possibile evitare i problemi che portano a una perdita di archiviazione permgen.)

22

Un esempio in cui questo è utile:

Impostazione -XX:+CMSPermGenSweepingEnabled -XX:+CMSClassUnloadingEnabled sul nostro Weblogic 10.3 JVM aiutarono risolvere un problema in cui l'implementazione di JAX-WS ha creato una nuova classe proxy per ogni chiamata di servizio web, portando infine a esaurimento della memoria errori.

Non era banale da rintracciare. Il seguente codice sempre restituito la stessa classe proxy per port

final MyPortType port = 
Service.create(
     getClass().getResource("/path/to.wsdl"), 
     new QName("http://www.example.com", "MyService")) 
    .getPort(
     new QName("http://www.example.com", "MyPortType"), 
     MyPortType.class); 

Internamente, questo proxy delegato a un'istanza di weblogic.wsee.jaxws.spi.ClientInstance, che ancora una volta ha delegato ad una nuova classe in cui $Proxy[nnnn]n è stato incrementato ad ogni chiamata. Quando si aggiungevano i flag, n veniva ancora incrementato, ma almeno quelle classi temporanee venivano rimosse dalla memoria.

Su una nota più generale, questo può essere molto utile quando si effettua pesante uso di Java riflessione e proxy attraverso java.lang.reflect.Proxy

+0

+1 per condividere l'esperienza reale. Abbiamo anche riscontrato questo problema su torquebox in cui il server ha generato un numero enorme di classi a causa dei processi di compilazione JRuby. – nurettin

+7

nota anche che '-XX: + CMSPermGenSweepingEnabled' è deprecato a favore di' -XX: + CMSClassUnloadingEnabled' – nurettin

+0

@nurettin: bello sapere, grazie per le informazioni –