Wenn Ihre Anwendung nicht interaktiv ist und GC-Pausen für Sie kein Problem darstellen, sollte es für 64-Bit-Java kein Problem geben, sehr große Heaps zu verarbeiten, selbst in Hunderten von GB. Wir haben auch keine Stabilitätsprobleme unter Windows oder Linux bemerkt.
Wenn Sie jedoch die GC-Pausen niedrig halten müssen, wird es wirklich schlimm:
Vergessen Sie den Standarddurchsatz, Stop-the-World-GC. Bei moderaten Heaps (<~ 30 GB) wird die Anwendung für einige zehn Sekunden und bei großen Heaps (> ~ 30 GB) für einige Minuten unterbrochen. Und der Kauf schnellerer DIMMs hilft nicht weiter.
Die beste Wahl ist wahrscheinlich der CMS-Collector, der von -XX: + UseConcMarkSweepGC aktiviert wird. Der CMS-Garbage Collector stoppt die Anwendung nur für die anfängliche Markierungsphase und die Bemerkungsphase. Für sehr kleine Heaps wie <4 GB ist dies normalerweise kein Problem, aber für eine Anwendung, die viel Müll und einen großen Heap erzeugt, kann die Bemerkungsphase ziemlich lange dauern - normalerweise viel weniger als ein vollständiger Stopp der Welt , kann aber dennoch ein Problem für sehr große Haufen sein.
Wenn der CMS-Garbage Collector nicht schnell genug ist, um den Betrieb zu beenden, bevor die dauerhafte Generation voll ist, greift er auf den Standard-Stop-the-World-GC zurück. Erwarten Sie ~ 30 oder mehr Sekunden lange Pausen für Haufen mit einer Größe von 16 GB. Sie können versuchen, dies zu vermeiden, indem Sie die langlebige Müllproduktionsrate Ihrer Anwendung so niedrig wie möglich halten. Beachten Sie, dass dieses Problem umso größer ist, je höher die Anzahl der Kerne ist, auf denen Ihre Anwendung ausgeführt wird, da das CMS nur einen Kern verwendet. Beachten Sie natürlich, dass es keine Garantie dafür gibt, dass das CMS nicht auf den STW-Kollektor zurückgreift. Und wenn dies der Fall ist, geschieht dies normalerweise bei Spitzenlasten, und Ihre Anwendung ist für einige Sekunden tot. Sie möchten wahrscheinlich keine SLA für eine solche Konfiguration signieren.
Nun, da ist das neue G1-Ding. Es wurde theoretisch entwickelt, um die Probleme mit CMS zu vermeiden, aber wir haben es versucht und festgestellt, dass:
- Der Durchsatz ist schlechter als der von CMS.
- Es sollte theoretisch vermeiden, zuerst die populären Speicherblöcke zu sammeln, erreicht jedoch bald einen Zustand, in dem fast alle Blöcke "populär" sind und die Annahmen, auf denen es basiert, einfach aufhören zu funktionieren.
- Schließlich gibt es für G1 immer noch den Stop-the-World-Fallback. Fragen Sie Oracle, wann dieser Code ausgeführt werden soll. Wenn sie "nie" sagen, fragen Sie sie, warum der Code dort ist. IMHO G1 lässt das riesige Heap-Problem von Java also wirklich nicht verschwinden, sondern macht es (wohl) nur ein wenig kleiner.
Wenn Sie Geld für einen großen Server mit großem Speicher haben, haben Sie wahrscheinlich auch Geld für eine gute, kommerzielle, hardwarebeschleunigte, pausenlose GC-Technologie, wie die von Azul. Wir haben einen ihrer Server mit 384 GB RAM und es funktioniert wirklich gut - keine Pausen, 0 Zeilen Stop-the-World-Code im GC.
Schreiben Sie den verdammten Teil Ihrer Anwendung, der in C ++ viel Speicher benötigt, wie es LinkedIn bei der Verarbeitung sozialer Grafiken getan hat. Sie werden dadurch immer noch nicht alle Probleme vermeiden (z. B. Heap-Fragmentierung), aber es wäre definitiv einfacher, die Pausen niedrig zu halten.
Ich bin CEO von Azul Systems, daher bin ich meiner Meinung nach zu diesem Thema offensichtlich voreingenommen! :) Davon abgesehen ...
Gil Tene, CTO von Azul, hat einen schönen Überblick über die mit der Garbage Collection verbundenen Probleme und einen Überblick über verschiedene Lösungen in seiner Präsentation Grundlegendes zur Java Garbage Collection und was Sie dagegen tun können. Weitere Informationen finden Sie in diesem Artikel: http: // www.infoq.com/articles/azul_gc_in_detail .
Azul's C4 Garbage Collector in unserer Zing JVM ist sowohl parallel als auch gleichzeitig und verwendet für die neue und die alte Generation denselben GC-Mechanismus, der in beiden Fällen gleichzeitig arbeitet und komprimiert. Am wichtigsten ist, dass C4 keinen Rückfall hat. Die gesamte Komprimierung wird gleichzeitig mit der laufenden Anwendung durchgeführt. Wir haben Kunden, die sehr groß sind (Hunderte von GByte), mit GC-Pausenzeiten im schlimmsten Fall von <10 ms und je nach Anwendung oft weniger als 1-2 ms.
Das Problem mit CMS und G1 besteht darin, dass der Java-Heapspeicher irgendwann komprimiert werden muss und beide Garbage Collectors die Welt stoppen / STW (dh die Anwendung anhalten), um die Komprimierung durchzuführen. Während CMS und G1 STW-Pausen auslösen können, werden sie nicht beseitigt. Azul's C4 eliminiert jedoch STW-Pausen vollständig und deshalb hat Zing selbst für gigantische Heap-Größen so niedrige GC-Pausen.
quelle
Wir haben eine Anwendung, für die wir 12-16 GB zuweisen, die aber im normalen Betrieb nur 8-10 erreicht. Wir verwenden die Sun JVM (haben IBMs ausprobiert und es war eine Katastrophe, aber das könnte unsererseits Unwissenheit gewesen sein ... Ich habe Freunde, die darauf schwören - die bei IBM arbeiten). Solange Sie Ihrer App Raum zum Atmen geben, kann die JVM große Heap-Größen mit nicht zu viel GC verarbeiten. Viel "zusätzlicher" Speicher ist der Schlüssel.
Linux ist fast immer stabiler als Windows und wenn es nicht stabil ist, ist es verdammt viel einfacher herauszufinden, warum. Solaris ist ebenfalls sehr solide und Sie erhalten auch DTrace :) Warum um alles in der Welt würden Sie mit diesen Lasten Vista oder XP verwenden? Sie bitten nur um Ärger. Mit den GC-Parametern machen wir nichts Besonderes. Wir setzen die minimale Zuordnung auf das Maximum, damit nicht ständig versucht wird, die Größe zu ändern, aber das ist es.
quelle
Ich habe über 60 GB Heap-Größen in zwei verschiedenen Anwendungen unter Linux und Solaris verwendet, wobei (offensichtlich) 64-Bit-Versionen der Sun 1.6 JVM verwendet wurden.
Ich habe nie Probleme mit der Garbage Collection mit der Linux-basierten Anwendung festgestellt, außer wenn ich mich der Heap-Größenbeschränkung näherte. Um die mit diesem Szenario verbundenen Probleme zu vermeiden (zu viel Zeit für die Speicherbereinigung), habe ich einfach die Speichernutzung im gesamten Programm so optimiert, dass die maximale Auslastung etwa 5 bis 10% unter einer Heap-Größenbeschränkung von 64 GB lag.
Bei einer anderen Anwendung, die unter Solaris ausgeführt wird, sind jedoch erhebliche Probleme bei der Speicherbereinigung aufgetreten, die viele Optimierungen erforderlich machten. Dies bestand hauptsächlich aus drei Schritten:
Aktivieren / Erzwingen der Verwendung des parallelen Garbage Collector über die JVM-Optionen -XX: + UseParallelGC -XX: + UseParallelOldGC sowie Steuern der Anzahl der über die Option -XX: ParallelGCThreads verwendeten GC-Threads. Weitere Informationen finden Sie unter " Optimierung der Garbage Collection für Java SE 6 HotSpot Virtual Machine ".
Umfangreiche und scheinbar lächerliche Einstellung lokaler Variablen auf "null", nachdem sie nicht mehr benötigt werden. Bei den meisten dieser Variablen handelte es sich um Variablen, die nach dem Verlassen des Gültigkeitsbereichs für die Speicherbereinigung in Frage gekommen sein sollten, und es handelte sich nicht um Speicherverlustsituationen, da die Referenzen nicht kopiert wurden. Diese "Hand-Holding" -Strategie zur Unterstützung der Speicherbereinigung war jedoch aus irgendeinem Grund für diese Anwendung unter der fraglichen Solaris-Plattform unerklärlich erforderlich.
Selektive Verwendung des System.gc () -Methodenaufrufs in Schlüsselcodeabschnitten nach längeren Zeiträumen temporärer Objektzuweisung. Ich bin mir der üblichen Vorbehalte gegen die Verwendung dieser Aufrufe und des Arguments bewusst, dass sie normalerweise unnötig sein sollten, aber ich fand, dass sie bei der Zähmung der Speicherbereinigung beim Ausführen dieser speicherintensiven Anwendung von entscheidender Bedeutung sind.
Die drei oben genannten Schritte machten es möglich, diese Anwendung in einer Heap-Auslastung von etwa 60 GB zu halten und produktiv auszuführen, anstatt außer Kontrolle zu geraten, bis die bestehende Heap-Größenbeschränkung von 128 GB erreicht war. Insbesondere der parallele Garbage Collector war sehr hilfreich, da große Garbage Collection-Zyklen teuer sind, wenn viele Objekte vorhanden sind, dh die für die große Garbage Collection erforderliche Zeit hängt von der Anzahl der Objekte im Heap ab.
Ich kann weder andere plattformspezifische Probleme in dieser Größenordnung kommentieren noch JVMs verwenden, die nicht von Sun (Oracle) stammen.
quelle
12 GB sollten mit einer anständigen JVM-Implementierung wie Suns Hotspot kein Problem sein. Ich würde Ihnen raten, den Concurrent Mark and Sweep-Kolllektor (-XX: + UseConcMarkSweepGC) zu verwenden, wenn Sie eine SUN VM verwenden. Andernfalls kann es zu langen "Stop the World" -Phasen kommen, in denen alle Threads während eines GC gestoppt werden.
Das Betriebssystem sollte keinen großen Unterschied für die GC-Leistung machen.
Sie benötigen natürlich ein 64-Bit-Betriebssystem und einen Computer mit genügend physischem RAM.
quelle
Ich empfehle auch, einen Heap-Dump zu erstellen und zu prüfen, wo die Speichernutzung in Ihrer App verbessert werden kann, und den Dump in etwas wie Eclipse's MAT zu analysieren . Auf der MAT-Seite finden Sie einige Artikel zum Einstieg in die Suche nach Speicherlecks. Sie können jmap verwenden, um den Speicherauszug mit etwas wie ...
quelle
Wie oben erwähnt, sollte der standardmäßige (komprimierende) Garbage Collector (GC) gut funktionieren, wenn Sie ein nicht interaktives Programm haben. Wenn Sie ein interaktives Programm haben und (1) nicht schneller Speicher zuweisen, als der GC mithalten kann, und (2) keine temporären Objekte (oder Sammlungen von Objekten) erstellen, die zu groß sind (im Verhältnis zur Gesamtsumme) maximaler JVM-Speicher), damit der GC umgehen kann, dann ist CMS für Sie.
Sie haben Probleme, wenn Sie ein interaktives Programm haben, bei dem der GC nicht genügend Raum zum Atmen hat. Das gilt unabhängig davon, wie viel Speicher Sie haben, aber je mehr Speicher Sie haben, desto schlimmer wird es. Dies liegt daran, dass CMS nicht genügend Arbeitsspeicher zur Verfügung steht, wenn der Arbeitsspeicher zu niedrig ist, während die komprimierenden GCs (einschließlich G1) alles anhalten, bis der gesamte Arbeitsspeicher auf Müll überprüft wurde. Diese Stop-the-World-Pause wird größer, je mehr Speicher Sie haben. Vertrauen Sie mir, Sie möchten nicht, dass Ihre Servlets länger als eine Minute pausieren. Ich habe eine detaillierte StackOverflow-Antwort zu diesen Pausen in G1 geschrieben.
Seitdem ist meine Firma zu Azul Zing gewechselt. Es kann immer noch nicht mit dem Fall umgehen, dass Ihre App wirklich mehr Speicher benötigt als Sie haben, aber bis zu diesem Moment läuft es wie ein Traum.
Aber natürlich ist Zing nicht kostenlos und seine spezielle Sauce ist patentiert. Wenn Sie weit mehr Zeit als Geld haben, schreiben Sie Ihre App neu, um einen Cluster von JVMs zu verwenden.
Am Horizont arbeitet Oracle an einem Hochleistungs-GC für Multi-Gigabyte-Heaps. Ab heute ist dies jedoch keine Option.
quelle
Wenn Sie zu 64-Bit wechseln, benötigen Sie mehr Speicher. Zeiger werden zu 8 Bytes anstelle von 4. Wenn Sie viele Objekte erstellen, kann dies auffallen, da jedes Objekt eine Referenz (Zeiger) ist.
Ich habe kürzlich 15 GB Speicher in Java mit der Sun 1.6 JVM ohne Probleme zugewiesen. Obwohl alles nur einmal vergeben wird. Nach dem anfänglichen Betrag wird nicht viel mehr Speicher zugewiesen oder freigegeben. Dies war unter Linux, aber ich kann mir vorstellen, dass die Sun JVM unter 64-Bit-Windows genauso gut funktioniert.
quelle
Sie sollten versuchen, visualgc für Ihre App auszuführen. Es ist ein Heap-Visualisierungstool, das Teil des jvmstat-Downloads unter http://java.sun.com/performance/jvmstat/ ist.
Es ist viel einfacher als das Lesen von GC-Protokollen.
Es hilft Ihnen schnell zu verstehen, wie die Teile (Generationen) des Heaps funktionieren. Während Ihr gesamter Heap 10 GB betragen kann, sind die verschiedenen Teile des Heaps viel kleiner. GCs im Eden-Teil des Haufens sind relativ billig, während volle GCs in der alten Generation teuer sind. Es ist eine gute Strategie, Ihren Haufen so zu dimensionieren, dass das Eden groß ist und die alte Generation kaum berührt wird. Dies kann zu einem sehr großen Gesamthaufen führen, aber was solls, wenn die JVM die Seite nie berührt, ist sie nur eine virtuelle Seite und muss keinen RAM belegen.
quelle
Vor ein paar Jahren habe ich JRockit und die Sun JVM für einen 12G-Haufen verglichen. JRockit hat gewonnen und die Unterstützung von Linux-Riesen-Seiten hat unseren Testlauf um 20% beschleunigt. YMMV als unser Test war sehr prozessor- / speicherintensiv und war hauptsächlich Single-Threaded.
quelle
Hier ist ein Artikel über gc von einem der Java Champions - http://kirk.blog-city.com/is_your_concurrent_collector_failing_you.htm
Kirk, der Autor, schreibt: "Schicken Sie mir Ihre GC-Protokolle
Ich bin derzeit daran interessiert, von Sun JVM produzierte GC-Protokolle zu studieren. Da diese Protokolle keine geschäftsrelevanten Informationen enthalten, sollten Bedenken hinsichtlich des Schutzes proriatärer Informationen ausgeräumt werden. Ich bitte Sie nur, mit dem Protokoll das Betriebssystem, die vollständigen Versionsinformationen für die JRE und alle von Ihnen festgelegten Heap / GC-bezogenen Befehlszeilenoptionen zu erwähnen. Ich würde auch gerne wissen, ob Sie Grails / Groovey, JRuby, Scala oder etwas anderes als oder neben Java ausführen. Die beste Einstellung ist -Xloggc:. Bitte beachten Sie, dass dieses Protokoll nicht verlängert wird, wenn es die Größenbeschränkung Ihres Betriebssystems erreicht. Wenn ich etwas Interessantes finde, gebe ich Ihnen gerne eine sehr kurze Zusammenfassung. ""
quelle
Ein Artikel von Sun über Java 6 kann Ihnen helfen: https://www.oracle.com/java/technologies/javase/troubleshoot-javase.html
quelle
Der maximale Speicher, den XP adressieren kann, beträgt 4 Gig ( hier ). Daher möchten Sie möglicherweise kein XP dafür verwenden (verwenden Sie ein 64-Bit-Betriebssystem).
quelle
sun hat seit einiger Zeit ein 64-Bit-JVM von itanium, obwohl itanium kein beliebtes Ziel ist. Die 64-Bit-JVMs von Solaris und Linux sollten genau das sein, wonach Sie suchen sollten.
Einige Fragen
1) Ist Ihre Anwendung stabil?
2) Haben Sie die App bereits in einer 32-Bit-JVM getestet?
3) Ist es in Ordnung, mehrere JVMs auf derselben Box auszuführen?
Ich würde erwarten, dass das 64-Bit-Betriebssystem von Windows in ungefähr einem Jahr stabil wird, aber bis dahin ist Solaris / Linux möglicherweise die bessere Wahl.
quelle