Seltsames GC-Verhalten der Scala-Schauspieler-Anwendung

9

Ich habe eine Anwendung, die ziemlich viele Akteure verwendet a>: 25.000 um genau zu sein. Es verwendet Scala 2.7.7 und läuft auf jdk6_u18 . Es hört und verarbeitet im Wesentlichen Marktdaten und hat sehr wenig Staat.

Es beginnt jeden Tag um 8.02 Uhr und innerhalb der Stunde ist es mit einem OutOfMemoryError abgestürzt. "Aha", sagst du, "du hast ein Speicherleck!" Nur wenn ich es neu starte, stürzt es nie , je für den Rest des Tages wieder ab! Dies trotz der Tatsache, dass sowohl der GC- als auch der CPU-Overhead bei der Öffnung der US-Märkte um 14.30 Uhr stark ansteigen.

Einige anekdotische Ergebnisse:

  • es läuft auf Solaris. Wenn ich es unter Linux ausgeführt habe, ist nie überhaupt abgestürzt .
  • Ich habe versucht, mit der Generierung von Heapgrößen zu arbeiten, mehr Speicher zuzuweisen usw. Ich denke, es macht keinen Unterschied
  • Das Verhalten des Kollektors scheint sich zu unterscheiden, wenn ich verbose:gc eingeschaltet habe

Ein paar Fragen stellen sich vor:

  1. Warum sollte das Verhalten dieses Programms zwischen Linux und Solaris anders sein?
  2. Warum unterscheidet sich das Verhalten zwischen 8.02 und 8,42?
  3. Ich habe gehört, dass die Bibliothek der Schauspieler einige Probleme mit dem Speicherverlust hatte. Was waren sie, wann waren sie behoben und wie sollte ich herausfinden, ob hier etwas "Ähnliches" vor sich geht? (Dinge in jhat usw.)
  4. zu suchen
  5. Hat jemand eine Idee, was da vor sich geht?

Ich versuche jetzt G1 , um zu sehen, ob das einen Unterschied macht. Ich werde diese Frage morgen aktualisieren!

Einige Ausgaben von G1 mit ausführlichen: gc on

Ich denke, ich habe es gerade in der Tat gefangen:

  

600,290: [Voller GC 255M- & gt; 144M (256M), 1,5772616 Sekunden]
  602,084: [GC-Pause (jung) 227M- & gt; 145M (256M), 0,0556769 Sekunden]   602,418: [Voller GC 254M- & gt; 144M (256M), 1,6415216 Sek.]
  604,279: [GC-Pause (jung) 227M- & gt; 145M (256M), 0,0415157 Sekunden]   604.602: [Voller GC 255M- & gt; 145M (256M), 1.6041762 Sek.]
  606.422: [GC-Pause (jung) 227M- & gt; 145M (256M), 0,0237441 Sekunden]
  606.710: [Voller GC 254M- & gt; 145M (256M), 1.6022185 Sekunden]

Und dann ein bisschen später (Sie können sehen, dass der vollständige GC länger gedauert hat und weniger zurückfordert)

  

849.084: [Voller GC 254M- & gt; 176M (256M), 1.9658754 Sek.]
  851,191: [GC-Pause (jung) 228M- & gt; 176M (256M), 0,0218611 Sek.]
  851,414: [Voller GC 254 M- & gt; 176 M (256 M), 1,9352357 s]]   853.492: [GC-Pause (jung) 228M- & gt; 176M (256M), 0,0224688 Sek.]
  853.716: [Voller GC 254M- & gt; 176M (256M), 1.9339705 Sek.]
  855.793: [GC-Pause (jung) 228M- & gt; 176M (256M), 0.0215707 Sek.]
  856.009: [Voller GC 254M- & gt; 176M (256M), 1.9805797 Sek.]
  858,137: [GC-Pause (jung) 228M- & gt; 176M (256M), 0,0223224 Sekunden]

Einige Ausgaben von G1 mit ausführlichen Angaben: gc off

Es ist wieder gut! * Seufz *

  

303.656: [GC-Pause (jung) 225M- & gt; 93M (256M), 0.1680767 sec]   308.060: [GC-Pause (jung) 226M- & gt; 94M (256M), 0.1793724 Sekunden]   312.746: [GC-Pause (jung) 227M- & gt; 93M (256M), 0.1674851 Sek.]
  316.162: [GC-Pause (jung) 227M- & gt; 95M (256M), 0.1826145 Sekunden]
  320,147: [GC-Pause (jung) 226M- & gt; 94M (256M), 0,1656664 Sekunden]   325.978: [GC-Pause (jung) 226M- & gt; 93M (256M), 0.1475760 Sek.]
  330,176: [GC-Pause (jung) 226M- & gt; 94M (256M), 0,1727795 Sekunden]

und viel, viel später ist es immer noch OK!

  

25882.894: [GC-Pause (jung) 224M- & gt; 125M (256M), 0.2126515 Sekunden]
  25884.880: [GC-Pause (jung) 224M- & gt; 126M (256M), 0.2059802 Sek.]
  25887,027: ​​[GC-Pause (jung) 224M- & gt; 125M (256M), 0,1851359 Sek.]
  25889.940: [GC-Pause (jung) 223M- & gt; 126M (256M), 0.2046496 Sek.]
  25891,567: [GC-Pause (jung) 224M- & gt; 126M (256M), 0,1600574 Sekunden]

und später noch ein vollständiger GC

  

37180.191: [GC-Pause (jung) 225M- & gt; 154M (256M), 0,1716404 Sekunden]
  37182.163: [GC-Pause (jung) (Anfangsmarkierung) 225M- & gt; 153M (256M) 37182.326: [GC-Concurrent-Mark-Start], 0.1622246 Sek.]
  37183.089: [GC-Begleitzeichen-Ende, 0.7635219 Sek.]
  37183.090: [Bemerkung GC, 0.0032547 Sek.]
  37183.093: [GC counter-count-start]
  37183.297: [GC countant-count-end, 0.2043307]
  37183,393: [GC-Reinigung 198 M & ndash; & gt; 198 M (256 M), 0,0068127 s]]   37183.400: [GC-gleichzeitigen-Bereinigung-Start]
  37183.400: [GC-Parallel-Cleanup-Ende, 0.0000393]
  37183.648: [GC-Pause (jung) 222M- & gt; 153M (256M), 0.1483041 sec]   37184.235: [GC-Pause (teilweise) 171M- & gt; 91M (256M), 0.2520714 Sekunden]
  37187,223: [GC-Pause (jung) 221M- & gt; 92M (256M), 0.1721220 Sekunden]

AKTUALISIEREN

Seit dem Wechsel zum G1 Garbage Collector auf jdk1.6.0_18 hat sich die Anwendung an drei aufeinanderfolgenden Tagen verhalten. Ich vermute, dass Erik in seiner Analyse der Situation korrekt ist, dass sich die VM in Hochdurchsatz-Fällen, in denen sie Objekte in die Dauergeneration befördert hat, in eine Todesspirale verwandelt.

    
oxbow_lakes 23.05.2017, 12:01
quelle

3 Antworten

4

Haben Sie Grund zu der Annahme, dass Ihr Heap langsam an Größe zunimmt? Es sieht so aus, als ob es in beiden Spuren wächst. Eine Sache, die ich bei vielen Gelegenheiten gemacht habe, ist, meinen Haufen zu reduzieren, um das Problem noch schlimmer zu machen. Allerdings ist 256M etwa die untere Grenze für Scala.

Eine Sache, die mir schon aufgefallen ist, ist, dass wenn du kurzlebige Objekte hast, die es wegen zu viel Druck aus der Eden-Generation herausholen, kann es dich allmählich töten. Dies kann passieren, wenn eine Aktivität ausbricht (vielleicht hast du morgens einen Stoß?) Und dein Eden-Raum ist nicht groß genug. Scala im Allgemeinen und Schauspieler im Besonderen machen Gebrauch von kleinen, kurzlebigen Objekten, und es scheint, als gäbe es diese magische Schwelle, die, wenn man erst einmal den Hügel überquert hat. So wird ein Lauf gut und der nächste stürzt ab und brennt.

Eine weitere Sache, die mir schon aufgefallen ist, ist, dass die GC-Einstellungen, die unter OSX / x86 gut funktionieren, oft nicht gut auf Sparc / Solaris und umgekehrt funktionieren. Wenn Sie auf CoolThreads sind, rate ich Ihnen, den GC so zu konfigurieren, dass ein GC-Thread pro Thread in Ihrem Scheduler / Pool vorhanden ist.

Was eine andere Sache hervorbringt - stellen Sie sicher, dass der Scheduler keine unnötigen neuen Threads erstellt. Es wird das manchmal tun. Ich würde sagen, Sie sollten fast immer manuell eine Obergrenze für die Threads festlegen. Ich weiß nicht, wie relevant es ist, aber eine interessante Tatsache über den Fork-Join-Scheduler, den Akteure standardmäßig verwenden, ist, dass sie für kurze, CPU-gebundene Aufgaben gedacht ist. Doing IO in den Threads, die es verwaltet, verschraubt seine Annahmen. Natürlich sollte es noch funktionieren, aber ...

Viel Glück! Ich habe viele, viele Tage meines Lebens für solche Probleme verloren.

Sehen Sie sich einige der folgenden Optionen an: Ссылка

Es sieht so aus, als ob Sie den Collective-Mark-Sweep-Collector verwenden. Versuchen Sie die Einstellung:

%Vor%     
Erik Engbrecht 03.02.2010, 03:41
quelle
1

An dieser Stelle frage ich mich, ob es sich lohnen würde, Ihre Schauspieler durch Lift's oder Akka zu ersetzen? Obwohl ich denke, dass es unwahrscheinlich ist, dass es ein Fehler mit ihnen ist, kitzeln sie möglicherweise nicht, was auch immer den Absturz verursacht.

    
Daniel C. Sobral 02.02.2010 13:00
quelle
0

Von meinem Punkt aus ist das Heap-Layout falsch. Alter Raum variiert von 93M am Anfang bis 176 bei hoher Belastung. Wie ich aus den Logs ersehe, ist die Generation ungefähr ~ 50mb / sec im Durchschnitt. Also, wenn Sie eine Pause von etwa 2 Sekunden bei voller GC bei einem Punkt von 176 MB haben, haben Sie keinen jungen Platz um neue Objekte zu erstellen. Meine Ratschläge:

  • Überprüfen Sie die Einstellungen für Survivor Spaces - Ihr alter Space wird auf 176M erhöht. neuen Raum zu reduzieren - offensichtlich ist es nicht Absicht
  • Setzen Sie NewSize explizit auf den gewünschten Wert, sagen Sie 128M

  • Erhöhen Sie die Gesamtgröße des Heapspeichers, um Objekte zu fördern, anstatt den vollständigen GC auszuführen

  • Sie haben sehr lange Pausen: gc 80mb & gt; 50 ms, ~ 120mb & gt; 150 ms. Versuchen Sie CMS stattdessen, ich glaube, es wird schneller sein. (Aber benchs)
Alexander Ashitkin 24.09.2011 21:29
quelle