2013-05-13 5 views
6

Ich bemerke ein seltsames Phänomen in meiner Anwendung. Ich speichere Objekte in einer Hashmap, nachdem ich sie an einen Server gesendet habe, und entferne sie, wenn die Antwort eintrifft.Java Garbage Collection Induzierte Latenz beeinträchtigt die Leistung

Ich bemerkte vor kurzem sehr langsam nach dem Laufen. Beim Überprüfen stellte ich fest, dass die Speicherbelegung bei 4 GB bleibt und dann auf weniger als 1 GB fällt. Ich vermute, dass es viele Objekte reinigt, weshalb die Performance so schlecht wird.

Also die Frage ist, warum es für Java zu Garbage Collect so spät dauert? Warten Sie also, bis der Heap voll ist, und führen Sie dann Garbage Collection durch. Sollte es nicht den Müll in regelmäßigen Abständen sammeln.

Die Objekte, die in der HashMap gespeichert werden, werden genau zu diesem Zeitpunkt erstellt, dh sie sind nicht langlebig.

Dies ist auf Linux (RHEL), Oracle JVM HotSpot 7. 64-Bit. 4 Kerne. Dies ist, wie die App ausgeführt wird:

java -jar -Xmx4g prog.jar

Anmerkung: Ich habe gesehen: Tuning garbage collections for low latency Aber jetzt möchte ich verstehen, warum der GC so lange dauert zu treten?

+2

Welche Flaggen sind Sie laufen das Programm mit? – FDinoff

+0

GC startet normalerweise erst, wenn der Heap fast voll ist. Die genauen Trigger variieren je nach JVM-Version und Einstellungen, aber insgesamt ist es in der Regel effizienter, einen großen GC selten gegen viele kleinere zu machen. Wie Sie jedoch festgestellt haben, ist dies nicht ideal für die Latenz. Wenn Sie eine minimale Latenzzeit wünschen, müssen Sie sie einstellen. (Oder finden Sie eine der wenigen verfügbaren GC-Implementierungen.) –

+0

@FDinoff keine anderen Flags als Standardwerte. im Grunde, java -jar prog.jar. –

Antwort

3

Es klingt wie Sie haben eine von zwei Fragen gehen: (. Wie auf HotSpot zum Mark-Compact generation)

  1. Wenn Sie halb langen Gegenständen gelebt, werden sie von junger Generation etwas älter bewegt werden Das heißt, sie hören auf, für die Sammlung gezählt zu werden und werden für einen langsameren GC gehalten.
  2. Ihr Heap-Speicher für junge Generationen ist zu klein für Ihr Nutzungsmuster, wodurch Objekte gezwungen werden, von einer jungen in eine ältere Generation verschoben zu werden.

Ich würde versuchen, Ihre junge Generation größer zu machen. Siehe Generational Garbage Collection und schau dir die verschiedenen Arten von Generationen an.

+0

Vergessen zu fügen: die Objekte, die in der HashMap gespeichert wird, wird genau zu dieser Zeit erstellt, das ist sie nicht langlebig. –

1

Also die Frage ist, warum es für Java zu Garbage Collect so spät dauert? Warten Sie also, bis der Heap voll ist, und führen Sie dann Garbage Collection durch. Sollte es nicht den Müll in regelmäßigen Abständen sammeln.

Sie verwenden den Garbage Collector "Throughput", und so soll sich der Collector verhalten. Es zielt darauf ab, den Systemdurchsatz zu maximieren, indem der Prozentsatz der CPU-Zeit minimiert wird, die für die Speicherbereinigung aufgewendet wird. Dies geschieht durch die einfache Strategie zu warten, bis der Heap (genauer gesagt der neue Objektraum) voll ist. Ceteris paribus, ist es am effizientesten:

  • Müll sammeln, wenn Sie viel davon haben, und
  • alles andere aufhören, während Sie Müll sammeln.

(Um zu verstehen, warum Sie die technischen Details, wie das Kopieren Kollektoren arbeiten ... verstehen müssen)

Natürlich, das bedeutet, dass Sie erhebliche Pausen bekommen.

Wenn Sie eine niedrige Latenzzeit benötigen, müssen Sie einen anderen Kollektor verwenden.Dies führt jedoch dazu, dass ein größerer Prozentsatz der tatsächlichen CPU-Zeit für die Speicherbereinigung ... und andere GC-bezogene Gemeinkosten aufgewendet wird.


Wenn Sie viele signifikante Pausen erhalten, kann auch ein Problem mit der relativen Größe von Leerzeichen auftreten. Bevor Sie sich jedoch mit den entsprechenden Parametern beschäftigen, sollten Sie die GC-Protokollierung aktivieren, um herauszufinden, was die Pausen verursacht und wie häufig sie sind.

0

Es ist einfach, weil der Standard-GC nicht startet, wenn der Heap voll ist.

Der Standard-Garbage Collector, der von der JVM ausgewählt wird, ist der Parallel GC. Ziel ist es, so viel Speicher wie möglich während der kürzesten Stop-the-World-Pause freizugeben. Es wird nicht in der jungen Generation beginnen, wenn Eden nicht voll ist. Ebenso wird es in der alten Generation nicht starten, wenn Tenured nicht voll ist.

Sie können zu CMS wechseln, wenn Sie regelmäßig Speicher aufräumen möchten. Verwenden Sie einfach die Flagge -XX:+UseConcMarkSweepGC. Es wird jedoch einen gewissen Mehraufwand für Ihre Anwendung bedeuten. Dies sind die Kosten für einen GC, der in regelmäßigen Abständen ausgeführt wird, ohne dass die Anwendung angehalten wird.

Also, um es zusammenzufassen:

  • Parallel GC hält die Anwendung startet nur, wenn es keine andere Wahl gibt

  • CMS gleichzeitig läuft ohne Ihre Anwendung zu pausieren, hat einige Kopf

Quelle: http://www.oracle.com/technetwork/java/javase/gc-tuning-6-140523.html