Was macht das JVM-Flag CMSClassUnloadingEnabled tatsächlich?


183

Ich kann für mein ganzes Leben keine Definition dessen finden, was das Java VM-Flag CMSClassUnloadingEnabledtatsächlich tut, abgesehen von einigen sehr unscharfen Definitionen auf hoher Ebene wie "Behebt Ihre PermGen-Probleme" ( was übrigens nicht der Fall ist).

Ich habe auf der Website von Sun / Oracle nachgesehen, und selbst die Optionsliste sagt nicht wirklich, was sie tut.

Basierend auf dem Namen des Flags schätze ich, dass der CMS Garbage Collector standardmäßig keine Klassen entlädt, und dieses Flag aktiviert es - aber ich kann nicht sicher sein.

Antworten:


219

Update Diese Antwort ist relevant für Java 5-7, Java 8 hat dies behoben: https://blogs.oracle.com/poonam/about-g1-garbage-collector,-permanent-generation-and-metaspace Kudos go to mt. Uulu

Für Java 5-7:

Der Standard-Oracle / Sun VM-Look auf der Welt lautet: Klassen sind für immer. Einmal geladen, bleiben sie im Gedächtnis, auch wenn es niemanden mehr interessiert. Dies ist normalerweise kein Problem, da Sie nicht so viele reine "Setup" -Klassen haben (= einmal für das Setup und dann nie wieder verwendet). Also, selbst wenn sie 1 MB aufnehmen, wen interessiert das?

Aber in letzter Zeit haben wir Sprachen wie Groovy, die zur Laufzeit Klassen definieren. Jedes Mal, wenn Sie ein Skript ausführen, werden eine (oder mehrere) neue Klassen erstellt, die für immer in PermGen bleiben. Wenn Sie einen Server betreiben, bedeutet dies, dass Sie einen Speicherverlust haben.

Wenn Sie CMSClassUnloadingEnabledden GC aktivieren, wird auch PermGen durchsucht und Klassen entfernt, die nicht mehr verwendet werden.

[EDIT] Sie müssen auch aktivieren UseConcMarkSweepGC(danke an Sam Hasler ). Siehe diese Antwort: https://stackoverflow.com/a/3720052/2541


17
Laut stackoverflow.com/a/3720052/2541 muss für CMSClassUnloadingEnabledjede Auswirkung UseConcMarkSweepGCauch festgelegt werden
Sam Hasler

1
Ich bin nicht sicher, wie sich dies auf die Idee der Verwendung von UseConcatSweepGC auswirkt, aber es scheint, dass kürzlich ein Fehler in CMSClassUnloadingEnabled behoben wurde. Es wird als hier behoben
Bill Rosmus

3
@ Kevin: Ja, auf jeden Fall. Siehe am unteren Rande des groovy.codehaus.org/Running : „Groovy Klassen dynamisch erstellt, aber die Standard - Java - VM GC nicht die PermGen Wenn Sie mit Java 6 oder höher hinzufügen -XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC. UseConcMarkSweepGCBenötigt wird , um zu ermöglichen CMSClassUnloadingEnabled.“
Aaron Digulla

1
Ein guter Artikel über die gemeinsame Verwendung von UseConcMarkSweepGC und CMSClassUnloadingEnabled. blog.redfin.com/devblog/2012/06/…
Victor

1
Nicht mehr gültig für 1.8: blogs.oracle.com/poonam/…
mt.uulu

35

Laut dem Blog-Beitrag Die vollständigste Liste der -XX-Optionen für Java JVM bestimmt, ob das Entladen von Klassen unter dem CMS-Garbage-Collector aktiviert ist. Der Standardwert ist false. Es gibt eine andere Option ClassUnloading, die truestandardmäßig aufgerufen wird und (vermutlich) die anderen Garbage Collectors betrifft.

Die Idee ist, dass der GC, wenn er feststellt, dass eine zuvor geladene Klasse nirgendwo mehr in der JVM verwendet wird, den Speicher zurückfordern kann, der zum Speichern des Klassenbytecodes und / oder des nativen Codes verwendet wird.

Das Festlegen von CMSClassUnloadingEnabled kann bei Ihrem Permgen-Problem hilfreich sein, wenn Sie derzeit den CMS-Collector verwenden . Es besteht jedoch die Möglichkeit, dass Sie das CMS nicht verwenden oder dass ein echter Speicherverlust im Zusammenhang mit Classloadern vorliegt. Im letzteren Fall wird Ihre Klasse dem GC niemals als unbenutzt erscheinen ... und daher niemals entladen.


Aaron Digulla sagt, "Klassen sind für immer". Dies ist selbst in der reinen Java-Welt nicht unbedingt der Fall. Tatsächlich ist die Lebensdauer einer Klasse an ihren Klassenlader gebunden. Wenn Sie also festlegen können, dass ein Klassenlader durch Müll gesammelt wird (und das ist nicht immer einfach), werden die geladenen Klassen auch mit Müll gesammelt.

Dies ist in der Tat der Fall, wenn Sie eine Webanwendung im laufenden Betrieb erneut bereitstellen. (Zumindest sollte dies passieren, wenn Sie die Probleme vermeiden können, die zu einem Permgen-Speicherleck führen.)


24

Ein Beispiel, wo dies nützlich ist:

Die Einstellung -XX:+CMSPermGenSweepingEnabled -XX:+CMSClassUnloadingEnabledin unserer Weblogic 10.3-JVM half bei der Lösung eines Problems, bei dem die JAX-WS-Implementierung für jeden Webdienstaufruf eine neue Proxy-Klasse erstellte, was schließlich zu Fehlern aufgrund von Speichermangel führte.

Es war nicht trivial zu verfolgen. Der folgende Code hat immer dieselbe Proxy-Klasse für zurückgegebenport

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

Intern wurde dieser Proxy an eine Instanz von weblogic.wsee.jaxws.spi.ClientInstancedelegiert, die wiederum an eine neue $Proxy[nnnn]Klasse delegiert nwurde, die bei jedem Aufruf erhöht wurde. Beim Hinzufügen der Flags nwurde noch erhöht, aber zumindest diese temporären Klassen wurden aus dem Speicher entfernt.

Allgemeiner kann dies sehr nützlich sein, wenn Java Reflection und Proxys stark genutzt werden java.lang.reflect.Proxy


+1 für den Austausch echter Erfahrungen. Wir hatten dieses Problem auch bei der Torquebox, bei der der Server aufgrund von JRuby-Kompilierungsprozessen eine große Anzahl von Klassen generiert hat.
Nurettin

7
Beachten Sie auch, dass -XX:+CMSPermGenSweepingEnabledzugunsten von-XX:+CMSClassUnloadingEnabled
nurettin

3
Eine echte Lösung für dieses Problem besteht jedoch darin, den Port einmal zu erstellen und wiederzuverwenden. So soll JAX-WS eingesetzt werden. Der Port ist außerdem 100% threadsicher.
Rustyx

@rustyx: Können Sie diese Behauptung mit einem maßgeblichen Link untermauern? Ich war immer sehr vorsichtig bei der Wiederverwendung von Proxys und Stubs für Webdienste ... Siehe z. B. Haftungsausschlüsse für Apache CXF . Oder diese Frage
Lukas Eder

1
@rukavitsya: Wie ich in meiner Antwort gesagt habe. Jedes Mal, wenn ich die obige Logik aufrief, wurde ein neuer Proxy erstellt
Lukas Eder
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.