Das erste, was ich über CMS gelernt habe, ist, dass es mehr Speicher benötigt als die anderen Kollektoren, etwa 25 bis 50 % mehr ist ein guter Ausgangspunkt. Dies hilft Ihnen, Fragmentierung zu vermeiden, da CMS keine Verdichtung vornimmt, wie es die Stop-the-World-Kollektoren tun würden. Zweitens sollte man Dinge tun, die dem Garbage Collector helfen: Integer.valueOf anstelle von new Integer, anonyme Klassen loswerden, sicherstellen, dass innere Klassen nicht auf unzugängliche Dinge zugreifen (private in der äußeren Klasse) und solche Dinge. Je weniger Müll, desto besser. FindBugs und das Nicht-Ignorieren von Warnungen werden dabei sehr helfen.
Was das Tuning angeht, so habe ich festgestellt, dass man mehrere Dinge ausprobieren muss:
-XX:+UseConcMarkSweepGC
Sagt der JVM, dass sie CMS in tenured gen verwenden soll.
Fixieren Sie die Größe Ihres Heaps: -Xmx2048m -Xms2048m Dies verhindert, dass GC Dinge wie das Vergrößern und Verkleinern des Heaps durchführen muss.
-XX:+UseParNewGC
bei der jungen Generation die parallele statt der seriellen Erfassung zu verwenden. Dies beschleunigt Ihre kleineren Sammlungen, insbesondere wenn Sie eine sehr große junge Generation konfiguriert haben. Eine große junge Generation ist im Allgemeinen gut, sollte aber nicht mehr als die Hälfte der alten Generation betragen.
-XX:ParallelCMSThreads=X
legt die Anzahl der Threads fest, die CMS verwenden soll, wenn es Dinge tut, die parallel ausgeführt werden können.
Die Bemerkung -XX:+CMSParallelRemarkEnabled ist standardmäßig seriell, was die Bearbeitung beschleunigen kann.
-XX:+CMSIncrementalMode ermöglicht eine höhere Laufzeit der Anwendung, indem die GC zwischen den Phasen verschoben wird
-XX:+CMSIncrementalPacing ermöglicht es der JVM, die Häufigkeit der Datenerfassung im Laufe der Zeit zu ändern
-XX:CMSIncrementalDutyCycleMin=X Minimale Zeitspanne für GC
-XX:CMSIncrementalDutyCycle=X Beginnen Sie damit, GC in diesem % der Zeit durchzuführen
-XX:CMSIncrementalSafetyFactor=X
Ich habe festgestellt, dass man generell niedrige Pausenzeiten erreichen kann, wenn man es so einrichtet, dass es im Grunde immer sammelt. Da die meiste Arbeit parallel erledigt wird, erhält man im Grunde regelmäßige, vorhersehbare Pausen.
-XX:CMSFullGCsBeforeCompaction=1
Dieser Punkt ist sehr wichtig. Sie sagt dem CMS-Kollektor, dass er die Sammlung immer abschließen soll, bevor er eine neue Sammlung beginnt. Andernfalls kann es passieren, dass er einen Haufen Arbeit wegwirft und neu beginnt.
-XX:+CMSClassUnloadingEnabled
Standardmäßig lässt das CMS Ihr PermGen wachsen, bis es Ihre Anwendung in ein paar Wochen tötet. Dies verhindert dies. Ihr PermGen würde nur wachsen, wenn Sie Reflection verwenden, oder String.intern missbrauchen, oder etwas Schlechtes mit einem Klassenlader tun, oder ein paar andere Dinge.
Man kann auch mit dem Überlebensverhältnis und dem Tenuring-Schwellenwert spielen, je nachdem, ob man langlebige oder kurzlebige Objekte hat und wie viel Objektkopien zwischen den Überlebensräumen man in Kauf nehmen kann. Wenn Sie wissen, dass alle Ihre Objekte langlebig sein werden, können Sie Überlebensräume der Größe Null konfigurieren, und alles, was eine Young-Gen-Sammlung überlebt, wird sofort getendert.