Erzwingt die vollständige Speicherbereinigung, wenn die Speicherbelegung einen bestimmten Schwellenwert überschreitet

8

Ich habe eine Serveranwendung, die in seltenen Fällen große Speicherblöcke reservieren kann.

Es ist kein Speicherleck, da diese Chunks vom Garbage Collector durch Ausführen einer vollständigen Garbage Collection zurück gefordert werden können . Bei der normalen Speicherbereinigung werden zu kleine Speicherbereiche freigegeben: In diesem Kontext ist dies nicht ausreichend.

Der Garbage Collector führt diese vollständigen GCs dann aus, wenn es für angemessen erachtet wird, wenn der Speicherbedarf der Anwendung sich dem mit -Xmx angegebenen zugewiesenen Maximum nähert.

Das wäre in Ordnung, wenn nicht diese problematischen Speicherzuweisungen in Bursts kommen und OutOfMemoryErrors verursachen könnten, weil der jvm nicht in der Lage ist Führen Sie einen GC schnell genug durch, um den erforderlichen Speicher freizugeben. Wenn ich System.gc () manuell vorher anrufe, kann ich diese Situation verhindern.

Jedenfalls würde ich es vorziehen, die Speicherzuweisung meines jvm nicht selbst überwachen zu müssen (oder die Speicherverwaltung in die Logik meiner Anwendung einzufügen); es wäre schön, wenn es einen Weg gäbe, die virtuelle Maschine mit einem Speicherschwellenwert zu betreiben, über den vollständige GCs automatisch ausgeführt würden, um den Speicher, den ich brauche, sehr früh freizugeben.

Lange Rede, kurzer Sinn: Ich brauche einen Weg (eine Befehlszeilenoption?), um den jvm so zu konfigurieren, dass er früh genug Speicher freigibt (dh einen vollständigen GC ausführt), wenn die Speicherbelegung einen bestimmten Schwellenwert erreicht. Es ist egal, ob das meine Anwendung hin und wieder verlangsamt.

Alles, was ich bis jetzt gefunden habe, sind Möglichkeiten, die Größe der Generationen zu ändern, aber das ist nicht das, was ich brauche (zumindest nicht direkt).

Ich würde Ihre Vorschläge begrüßen,

Silvio

P.S. Ich arbeite an einem Weg, um große Zuweisungen zu vermeiden, aber es könnte eine lange Zeit erfordern und meine App braucht in der Zwischenzeit ein wenig Stabilität

UPDATE : Analysieren der App mit jvisualvm, kann ich sehen, dass das Problem in der alten Generation ist

    
Silvio Donnini 15.03.2010, 16:59
quelle

7 Antworten

6

Von hier (dies ist eine 1.4.2 Seite, aber die gleiche Option sollte in allen Sun JVMs existieren):

Wenn Sie den CMS-Garbage Collector verwenden (von dem ich glaube, dass der Server standardmäßig aktiviert ist), ist die gewünschte Option

%Vor%

Dabei steht% für den verwendeten% Speicher, der einen vollständigen GC auslöst.

Fügen Sie hier Disclaimer ein, bei denen Sie mit GC-Parametern herumhantieren können, was zu schwerwiegenden Leistungsproblemen führen kann, die stark von der Maschine abweichen usw.

    
Sbodd 15.03.2010, 17:09
quelle
3

Wenn Sie große Objekte zuweisen, die nicht in die junge Generation passen, werden sie sofort im festgelegten Generierungsbereich zugewiesen. Dieser Speicherplatz wird nur GC'ed, wenn ein Voll-GC ausgeführt wird, den Sie versuchen, zu erzwingen.

Ich bin mir jedoch nicht sicher, ob das Ihr Problem lösen würde. Sie sagen "JVM kann einen GC nicht schnell genug durchführen". Selbst wenn Ihre Zuweisungen in Bursts erfolgen, wird die VM bei jeder Zuweisung prüfen, ob genügend Speicherplatz für diese Zuweisung verfügbar ist. Wenn nicht - und wenn das Objekt für die junge Generation zu groß ist -, wird es einen vollständigen GK geben, der "die Welt stoppen" sollte, wodurch verhindert wird, dass neue Allokationen überhaupt stattfinden. Sobald der GC abgeschlossen ist, wird Ihr neues Objekt zugeordnet.

Wenn kurz danach in Ihrem Burst die zweite große Allokation angefordert wird, wird es wieder dasselbe tun. Abhängig davon, ob das ursprüngliche Objekt noch benötigt wird, ist es entweder möglich, es erfolgreich zu GC zu machen, wodurch Platz für die nächste Zuweisung geschaffen wird, oder es schlägt fehl, wenn auf die erste Instanz noch Bezug genommen wird.

Sie sagen "Ich brauche einen Weg [...], um frühzeitig eine gute Menge an Speicher freizugeben (d. h. einen vollständigen GC durchzuführen), wenn die Speicherbelegung einen bestimmten Schwellenwert erreicht". Dies kann per definitionem nur dann gelingen, wenn in Ihrer Anwendung nicht mehr auf "viel Speicher" referenziert wird.

Nach dem, was ich hier verstehe, haben Sie möglicherweise eine Race-Bedingung, die Sie manchmal vermeiden können, wenn Sie manuelle GC-Anfragen einfügen. Im Allgemeinen sollten Sie sich über diese Dinge nie Gedanken machen müssen - aus meiner Erfahrung kommt ein OutOfMemoryError nur dann vor, wenn tatsächlich zu viele Zuordnungen vorhanden sind, um gleichzeitig in den Heap zu passen. In allen anderen Situationen sollte das "einzige" Problem eine Leistungsverschlechterung sein (die je nach den Umständen extrem werden kann, aber dies ist ein anderes Problem).

Ich schlage vor, dass Sie weitere Analysen des genauen Problems durchführen, um dies auszuschließen. Ich empfehle das VisualVM-Tool, das mit Java 6 geliefert wird. Starten Sie es und installieren Sie das VisualGC-Plugin. Dadurch können Sie die verschiedenen Speichergenerationen und ihre Größen sehen. Außerdem gibt es eine Fülle von GC-Protokollierungsoptionen, je nachdem, welche VM Sie verwenden. Einige Optionen wurden in anderen Antworten erwähnt.

Die anderen Optionen zum Auswählen des zu verwendenden GC und zum Optimieren von Schwellenwerten sollten in Ihrem Fall keine Rolle spielen, da sie alle davon abhängig sind, dass genügend Speicher verfügbar ist, um alle Objekte zu enthalten, die Ihre Anwendung zu einem bestimmten Zeitpunkt benötigt. Diese Optionen können hilfreich sein, wenn Sie Leistungsprobleme im Zusammenhang mit schwerer GC-Aktivität haben, aber ich befürchte, dass sie in Ihrem speziellen Fall nicht zu einer Lösung führen.

Sobald Sie mehr Vertrauen in das haben, was tatsächlich passiert, wird das Finden einer Lösung einfacher.

    
Daniel Schneller 15.03.2010 17:17
quelle
1

Weißt du, welche der Garbage Collection-Pools zu groß werden? .... d. eden vs. überlebender Raum? (Probieren Sie die JVM-Option -Xloggc:<file> log GC status to a file with time stamps ) ... Wenn Sie das wissen, sollten Sie in der Lage sein, die Größe des betroffenen Pools mit einer der hier erwähnten Optionen zu ändern: Hotspot-Optionen für Java 1.4

Ich weiß, dass diese Seite für die 1.4 JVM ist. Ich kann nicht die gleichen -X-Optionen in meinen aktuellen 1.6 Hilfefunktionen für die Installation finden, es sei denn, das Einstellen dieser individuellen Poolgrößen ist eine nicht standardmäßige, nicht standardmäßige Funktion!

    
James B 15.03.2010 17:12
quelle
1

Die JVM soll nur OutOfMemoryError nach werfen, nachdem versucht wurde, Speicher über die Garbage-Collection freizugeben (nach beiden Angaben) die API-Dokumentation für OutOfMemoryError und die JVM-Spezifikation ). Daher sollten Ihre Versuche, die Speicherbereinigung zu erzwingen, keinen Unterschied machen. Es könnte also etwas Wichtigeres dabei sein - entweder ein Problem mit Ihrem Programm, das Referenzen nicht richtig löscht, oder, weniger wahrscheinlich, einen JVM-Fehler.

    
Dan Dyer 15.03.2010 17:18
quelle
1

Es gibt eine sehr detaillierte Erklärung, wie GC hier funktioniert Es listet Parameter auf, um den für verschiedene Speicherpools / Generationen verfügbaren Speicher zu steuern.

    
quelle
0

Versuchen Sie, die Option -server zu verwenden. Es aktiviert paralleles gc und Sie werden etwas Leistungserhöhung haben, wenn Sie Multi-Core-Prozessor verwenden.

    
Artic 15.03.2010 17:04
quelle
0

Haben Sie versucht, mit G1 gc zu spielen? Es sollte ab 1.6.0u14 verfügbar sein.

    
mindas 15.03.2010 17:09
quelle