Playframework: Play2 OOM gibt kein .hprof-Log aus

Erstellt am 25. Feb. 2014  ·  5Kommentare  ·  Quelle: playframework/playframework

Ich betreibe derzeit ein Play! 2.2.1 Instanz auf EC2-Mikro. Ich bin auf ein Problem gestoßen, bei dem der Linux-Oom-Killer läuft und das Play! Beispiel. Ich habe erwartet, dass der Prozess eine .hprof-Datei ausgibt, damit ich sie überprüfen kann, aber dies scheint nicht der Fall zu sein.

Spielt! Benötigen Sie eine spezielle jvm-Option oder ein Flag, um .hprof zu speichern? Ich füge gerade -J-XX:+HeapDumpOnOutOfMemoryError hinzu, aber die Datei wird immer noch nicht ausgegeben

Unten sind mehr Details...

Ich verpacke mein Play! Verteilung mit:

sudo play dist

Um mein Play! Instanz führe ich wie folgt aus:

nohup sudo sh ./bin/play-server -mem 512 -J-server -Dconfig.resource=application-prod.conf -Dlogger.resource=application-logger-prod.xml -Dhttp.port=9000 -J-javaagent:/web/newrelic/newrelic.jar -Dnewrelic.bootstrap_classpath=true -J-XX:+HeapDumpOnOutOfMemoryError &

Ich kann das Protokoll von oom killer in /var/log/messages sehen:

Feb 24 06:33:55 ip-10-138-72-107 kernel: [562140.124986] java invoked oom-killer: gfp_mask=0x201da, order=0, oom_adj=0, oom_score_adj=0
Feb 24 06:33:55 ip-10-138-72-107 kernel: [562140.125007] java cpuset=/ mems_allowed=0
Feb 24 06:33:55 ip-10-138-72-107 kernel: [562140.125015] Pid: 26972, comm: java Not tainted 3.4.73-64.112.amzn1.x86_64 #1
Feb 24 06:33:55 ip-10-138-72-107 kernel: [562140.125022] Call Trace:
...
Feb 24 06:33:55 ip-10-138-72-107 kernel: [562140.127374] Out of memory: Kill process 26921 (java) score 891 or sacrifice child
Feb 24 06:33:55 ip-10-138-72-107 kernel: [562140.127383] Killed process 26921 (java) total-vm:2050524kB, anon-rss:558636kB, file-rss:0kB

Hilfreichster Kommentar

OOM Killer ist eine Schlampe. Es hat nichts mit dem Java-Heap zu tun, daher hilft es nicht, einen Heap-Dump auf oome zu setzen. Wenn Sie Linux nach Arbeitsspeicher fragen, erhalten Sie im Grunde einen Hinweis, auch wenn es nicht so viel Arbeitsspeicher zur Verfügung hat. Es weist den Speicher erst dann zu, wenn Sie ihn verwenden. Dies ist, was es tun soll, beispielsweise eine Stapelgröße von 2 Megabyte pro Thread und 10000 Threads zu haben, die theoretisch 20 GB Speicher benötigen, aber Sie haben diesen Speicher nicht auf dem Computer. Die meisten Threads verwenden nicht annähernd 2 MB Stack, daher wird nie der Speicher zugewiesen, den sie nicht verwenden.

Aber was passiert dann, wenn alles beginnt, den zugewiesenen Speicher zu verwenden, aber kein Speicher verfügbar ist, um träge zugewiesen zu werden? Geben Sie OOM-Killer ein. Linux wählt einen Prozess zum Beenden aus, der nach dem Beenden genügend Speicher zum Zuweisen freigibt. Da Java-Prozesse viel Speicher beanspruchen, wählt es sehr oft einen Java-Prozess aus. Es sendet ein SIGKILL, das bedeutet kein Core-Dump und keine Chance für die JVM, irgendetwas zu tun, um zu versuchen, zu bereinigen oder ordnungsgemäß herunterzufahren.

Dies funktioniert gut für Dinge wie PHP-Apps, bei denen jede Anfrage einem Prozess entspricht. Töte den größten Apache-Arbeiter. Problem gelöst. Für Java-Apps ist dies die dümmste Funktion aller Zeiten.

Was können Sie dagegen tun? Nicht viel, es gibt einige Dinge, die Sie im Linux-Kernel einstellen können, aber Sie können ihn nicht ganz ausschalten, und alles, was ich darüber gelesen habe, klingt, als wäre es einfach nicht praktikabel, Linux dazu zu bringen, dies nicht zu tun.

Hier ist, was Sie tun müssen:

  • 512 MB sind zu viel, eine Mikroinstanz hat nur ungefähr 600 MB, das Betriebssystem benötigt etwas und die JVM verwendet mehr als nur ihre Heaps. Stellen Sie Ihre Heap-Größe auf 256 MB ein. Dies sollte für eine kleine Play-App in Ordnung sein.
  • Stellen Sie sicher, dass sich auf dem Server nichts anderes befindet, das viel Speicher verbrauchen könnte. Wenn ja, beheben Sie es. Wenn Sie Apache oder ähnliches ausführen, ist dies ein guter Ort, um mit der Suche zu beginnen.
  • Ich bin mir nicht sicher, ob es möglich ist, einer EC2-Mikroinstanz eine Auslagerungsdatei hinzuzufügen. Wenn dies der Fall ist, erhalten Sie einen Puffer, bevor der OOM-Killer zuschlägt.

Wie auch immer, das hat nichts mit Play zu tun, also schließe ich.

Alle 5 Kommentare

OOM Killer ist eine Schlampe. Es hat nichts mit dem Java-Heap zu tun, daher hilft es nicht, einen Heap-Dump auf oome zu setzen. Wenn Sie Linux nach Arbeitsspeicher fragen, erhalten Sie im Grunde einen Hinweis, auch wenn es nicht so viel Arbeitsspeicher zur Verfügung hat. Es weist den Speicher erst dann zu, wenn Sie ihn verwenden. Dies ist, was es tun soll, beispielsweise eine Stapelgröße von 2 Megabyte pro Thread und 10000 Threads zu haben, die theoretisch 20 GB Speicher benötigen, aber Sie haben diesen Speicher nicht auf dem Computer. Die meisten Threads verwenden nicht annähernd 2 MB Stack, daher wird nie der Speicher zugewiesen, den sie nicht verwenden.

Aber was passiert dann, wenn alles beginnt, den zugewiesenen Speicher zu verwenden, aber kein Speicher verfügbar ist, um träge zugewiesen zu werden? Geben Sie OOM-Killer ein. Linux wählt einen Prozess zum Beenden aus, der nach dem Beenden genügend Speicher zum Zuweisen freigibt. Da Java-Prozesse viel Speicher beanspruchen, wählt es sehr oft einen Java-Prozess aus. Es sendet ein SIGKILL, das bedeutet kein Core-Dump und keine Chance für die JVM, irgendetwas zu tun, um zu versuchen, zu bereinigen oder ordnungsgemäß herunterzufahren.

Dies funktioniert gut für Dinge wie PHP-Apps, bei denen jede Anfrage einem Prozess entspricht. Töte den größten Apache-Arbeiter. Problem gelöst. Für Java-Apps ist dies die dümmste Funktion aller Zeiten.

Was können Sie dagegen tun? Nicht viel, es gibt einige Dinge, die Sie im Linux-Kernel einstellen können, aber Sie können ihn nicht ganz ausschalten, und alles, was ich darüber gelesen habe, klingt, als wäre es einfach nicht praktikabel, Linux dazu zu bringen, dies nicht zu tun.

Hier ist, was Sie tun müssen:

  • 512 MB sind zu viel, eine Mikroinstanz hat nur ungefähr 600 MB, das Betriebssystem benötigt etwas und die JVM verwendet mehr als nur ihre Heaps. Stellen Sie Ihre Heap-Größe auf 256 MB ein. Dies sollte für eine kleine Play-App in Ordnung sein.
  • Stellen Sie sicher, dass sich auf dem Server nichts anderes befindet, das viel Speicher verbrauchen könnte. Wenn ja, beheben Sie es. Wenn Sie Apache oder ähnliches ausführen, ist dies ein guter Ort, um mit der Suche zu beginnen.
  • Ich bin mir nicht sicher, ob es möglich ist, einer EC2-Mikroinstanz eine Auslagerungsdatei hinzuzufügen. Wenn dies der Fall ist, erhalten Sie einen Puffer, bevor der OOM-Killer zuschlägt.

Wie auch immer, das hat nichts mit Play zu tun, also schließe ich.

Mir ist gerade aufgefallen, dass die Play APP seit einiger Zeit ausgefallen ist, aber ich kann keine Informationen finden.
Dann ist mir aufgefallen, dass der Linux OOM Killer auch.
danke @jroper für diese Informationen.
Ich denke, diese Informationen sollten im Play-Benutzerhandbuch veröffentlicht werden

Vielen Dank für alle Details in Ihrer Antwort. Dies wird definitiv dazu beitragen, ein weiteres OOM zu verhindern, aber meine Besorgnis, dass etwas in meinem Code zu viel Heap-Speicherplatz benötigt, wird nicht ausgeräumt. Ich dachte, eine .hprof-Datei würde ausgegeben, wenn ich den Parameter -J-XX:+HeapDumpOnOutOfMemoryError setze. Die .hprof-Datei wäre wirklich hilfreich, um alle Threads und ihre Stack-Traces zum Zeitpunkt des oom-Killers zu untersuchen.

Wie ich bereits sagte, ist das OOM, das Sie gesehen haben, KEIN Java-OOM, sondern ein Linux-Ding. Javas OOME und dieses OOM, das Sie sehen, sind völlig unterschiedlich. Sofern Sie in Ihren Anwendungsprotokollen nicht sehen, dass Java einen OutOfMemoryError ausgelöst hat, haben Sie kein Problem damit, dass Ihr Programm zu viel Heap verwendet.

Die Sache, die zu viel Heap-Speicherplatz erzeugt, ist, dass Sie die JVM so konfigurieren, dass sie 512 MB verwendet. Der JVM ist ein Junggeselle, der gerade von zu Hause ausgezogen ist, er räumt den Müll auf seinem Haufen nicht auf, bis der Haufen voller Müll ist. Wenn Sie ihm eine maximale Heap-Größe von 512 MB mitteilen, wird es, selbst wenn es nur 10 MB benötigt, die Heap-Größe weiter auf die maximale Heap-Größe erhöhen und nur dann eine GC durchführen. Und selbst nachdem es eine Garbage Collection durchgeführt hat, verwendet es die JVM aus Sicht des Betriebssystems immer noch - es gibt diesen Speicher nicht zurück an das Betriebssystem, sondern hängt daran. So funktioniert der JVM-Heap, er nimmt so viel Speicher vom Betriebssystem und behält ihn.

Wenn Sie herausfinden möchten, wie viel Heap Ihre Anwendung tatsächlich verwendet, verbinden Sie jconsole damit, gehen Sie zur Registerkarte "Speicher", klicken Sie auf die Schaltfläche, um eine vollständige GC durchzuführen, und sehen Sie dann, wie viel Speicher der Heap verwendet.

Tolle Erklärung. Ich war mir der ganzen Komplexität der GC überhaupt nicht bewusst. Danke dafür!

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen