2016-05-19 10 views
5

Ich werde in Kürze versuchen, das Problem zu erklären. Ich arbeite in der Lieferkette Domain, wo wir mit Artikeln/Produkten und SKUs beschäftigen.Schlechte Leistung durch Java Garbage Collector? Brauchen Sie Vorschläge

Angenommen, mein gesamtes Problem ist 1 Million SKUs und ich führe einen Algorithmus. Jetzt wird meine JVM-Heap-Größe als 4 GB angegeben.

Ich kann nicht alle SKUs auf einmal verarbeiten, da ich viel mehr Speicher brauche. Also, ich teile das Problem in kleinere Mengen aufgeteilt. Jede Charge enthält alle zugehörigen SKUs, die zusammen verarbeitet werden müssen.

Jetzt führe ich mehrere Iterationen durch, um den gesamten Datensatz zu verarbeiten. Sagen wir, wenn jede Charge ca. 5000 SKUs, ich werde 200 Iterationen/Schleifen haben. Alle Daten für die 5000 SKUs sind erforderlich, bis die Charge die Verarbeitung abgeschlossen hat. Wenn jedoch der nächste Stapel gestartet wird, sind die vorherigen Stapeldaten nicht erforderlich und können daher als Müll gesammelt werden.

Dies ist das Problem Hintergrund. Kommen wir jetzt zu dem speziellen Leistungsproblem aufgrund von GC - . Jede Charge dauert etwa 2-3 Sekunden, um fertig zu werden. Jetzt, innerhalb dieser Zeit, kann GC keine Objekte mehr freigeben, da alle Daten bis zum Ende der Verarbeitung eines bestimmten Stapels benötigt werden. So verschiebt GC alle diese Objekte auf alte Gen (Wenn ich auf Ihrenkit Profiler schaue, dann gibt es kaum etwas in der neuen Generation). Also, altes Gen wächst schneller und es wird ein vollständiger GC benötigt, was mein Programm sehr langsam macht. Gibt es eine Möglichkeit, den GC in einem solchen Fall zu tunen, oder kann ich meinen Code ändern, um die Speicherzuweisung auf andere Weise vorzunehmen?

PS - wenn jede Charge sehr klein ist, sehe ich dieses Problem nicht. Ich glaube, das liegt daran, dass der GC in der Lage ist, Objekte schnell genug freizugeben, da der Stapel schneller abgeschlossen wird und somit Objekte in der alten Generation nicht verschoben werden müssen.

+0

Hat der ** Profiler ** Ihnen gesagt, dass es mehr als 10% der Zeit in Anspruch nimmt, Müll zu sammeln? Oder ist es eine Vermutung? – RobAu

+0

Ändern Sie die Tenuring-Schwelle. Wie hängt es von Ihrem GC ab - welchen GC verwenden Sie? –

+0

Wie lange dauert der vollständige GC? –

Antwort

3

First Google hit zeigt an, dass Sie -XX:NewRatio verwenden können, um eine größere neue Generierungsgröße im Vergleich zur alten Generation festzulegen.

+1

Findest du nicht neu zu erhöhen Generationsgröße wird die Sammelzeit für neue Gen erhöhen. Wenn Sie die Größe der neuen Generation erhöhen, dann behandeln Sie die neue Generation als alte Generation. Es wird eine ähnliche GC-Zeit im Vergleich zu der alten GC-Zeit benötigen. IMO jede GC Politik würde in diesem Fall nicht viel helfen. Bitte korrigieren Sie, wenn ich falsch liege. –

+1

@nachiketkate guter Punkt. Ich bin sicherlich kein Experte, aber mein Verständnis war immer, dass [es ist allgemein bekannt, dass es effizienter ist, junge als junge Generationen zu gießen] (http://www.javaspecialists.eu/archive/Issue115.html). Aber vielleicht ist dieser Vergleich unfair, wenn man annimmt, dass das junge Gen kleiner als alt ist. –

1

Sie müssen die -XX: NewRatio wie in der anderen Antwort erwähnt anpassen.

Sie können mit der Einstellung -XX: NewRatio = 1 beginnen, was bedeutet, dass Ihre alte Generation und junge Generation den verfügbaren Heapspeicher gleichmäßig teilen.

Weitere Informationen darüber, wie dieser Flag arbeitet zusammen mit anderer Speichereinstellung Fahnen: https://docs.oracle.com/cd/E19900-01/819-4742/abeik/index.html

+0

Bereits mit New Ratio gespielt ... Hat in gewissem Maße geholfen, aber marginal – Shiladitya

+0

Wenn Sie marginal sagen, was sind die NewRatios, die Sie ausprobiert haben? Was war die Verbesserung? – Vijay

+0

Ich bekomme die beste Leistung mit NEWRATIO = 3/4 – Shiladitya

1

Betrachten object pool pattern verwenden.

I.e. Erstellen Sie einen Pull von 5000 SKUs, und initialisieren Sie dann für jeden Stapel jedes dieser Objekte mit neuen Daten. Auf diese Weise werden Sie keine Probleme mit GC haben, da der Pull alles ist, was Sie zuordnen müssen.

+0

Danke, ich versuche etwas ähnliches. Aber nicht viel Erfolg – Shiladitya

0

Ein paar Tipps:

  1. prüfen Speicherlecks mit Profilierwerkzeuge wie visualvm oder MAT
  2. Wenn Sie keine Speicherlecks haben, überprüfen Sie aktuelle Speicher genug ist oder nicht. Wenn nicht, reservieren Sie genügend Speicherplatz.
  3. Von Ihrer Problemstellung, oldGen wächst und es verursacht FullGC. Sie haben den verwendeten Garbage Collector nicht angegeben.Da Sie Speicher> = 4 GB verwenden, sollten Sie G1GC alrogithm versuchen. In G1GC können Sie die meisten Standardwerte beibehalten, mit Ausnahme von Schlüsselparametern wie pause time goal, region size, parallel gc threads etc.

diese SE Frage Siehe für weitere Informationen:

Java 7 (JDK 7) garbage collection and documentation on G1

0

Ich weiß, das wenig zu spät ist, aber immer noch ..

spielte ich viel herum mit JVM GC-Optionen, die geholfen ein wenig. Gute Sache ist, dass ich viel mehr über GC in dem Prozess gelernt habe :)

Schließlich habe ich eine Art Objekt-Pooling gemacht. Da der Job in Stapeln verarbeitet wird und jeder Stapel ungefähr die gleiche Größe hat und die gleiche Anzahl an Objekten verwendet, habe ich einen Pool von Objekten erstellt, der für jeden Stapel neu erstellt wurde, anstatt die Objekte in jedem Stapel zu erstellen und zu zerstören. Am Ende jedes Stapels setze ich nur die Objekte (Arrays auf -1 usw.) zurück. Und am Anfang des nächsten Stapels verwende ich diese Objekte erneut, indem ich sie neu initialisiere. Auch für Multithread-Fälle werden diese Pools als ThreadLocals definiert, um den Synchronisationsaufwand zu vermeiden.