Cosa fa effettivamente JVM flag CMSClassUnloadingEnabled?

Non posso per la vita di me trovare una definizione di ciò che effettivamente fa il flag Java VM CMSClassUnloadingEnabled , a parte alcune definizioni molto sfocate di alto livello come “sbarazzarsi dei tuoi problemi PermGen” ( che non è vero , btw).

Ho consultato il sito Sun / Oracle e anche l’elenco delle opzioni in realtà non dice quello che fa.

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

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

Per Java 5-7:

L’aspetto standard di Oracle / Sun VM sul 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 poiché non si hanno tante classi puramente “di setup” (= usate una volta per l’installazione 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 runtime. 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 abiliti CMSClassUnloadingEnabled il GC spazzerà anche PermGen e rimuoverà le classi che non vengono più utilizzate.

[EDIT] Dovrai abilitare UseConcMarkSweepGC (grazie a Sam Hasler ). Vedi questa risposta: https://stackoverflow.com/a/3720052/2541

Secondo il post sul blog L’elenco più completo di opzioni -XX per Java JVM , determina se lo scaricamento delle classi è abilitato nel garbage collector CMS. Il valore predefinito è false . C’è un’altra opzione chiamata ClassUnloading che è true per impostazione predefinita che (presumibilmente) influenza gli altri garbage collector.

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

L’impostazione di CMSClassUnloadingEnabled potrebbe aiutare con il problema di permgen se si sta attualmente utilizzando il programma di raccolta 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 class non apparirà mai al GC da non usare … e quindi non verrà mai scaricata.


Aaron Digulla dice che “le lezioni sono per sempre”. Questo non è assolutamente vero, anche nel mondo puramente Java. In effetti, la durata di una class è 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 esegui una ridistribuzione a caldo di una webapp. (O almeno, questo è quello che dovrebbe succedere, se è ansible evitare i problemi che portano a una perdita di archiviazione permgen.)

Un esempio in cui questo è utile:

Impostazione -XX:+CMSPermGenSweepingEnabled -XX:+CMSClassUnloadingEnabled sul nostro Weblogic 10.3 JVM ha aiutato a risolvere un problema in cui l’implementazione JAX-WS ha creato una nuova class proxy per ogni chiamata al servizio web, portando infine a errori di memoria insufficiente.

Non era banale da tracciare. Il codice seguente ha sempre restituito la stessa class proxy per la 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 di nuovo delegato a una nuova class $Proxy[nnnn] dove n stato incrementato ad ogni chiamata. Quando si aggiungevano i flag, n veniva comunque incrementato, ma almeno quelle classi temporanee venivano rimosse dalla memoria.

In una nota più generale, questo può essere molto utile quando si fa un uso pesante della riflessione e dei proxy Java attraverso java.lang.reflect.Proxy