2013-08-16 8 views
6

Ich habe eine Berechnung in ST, die Speicher durch eine Data.Vector.Unboxed.Mutable reserviert. Der Vektor wird nie gelesen oder geschrieben, noch wird irgendeine Referenz außerhalb von runST beibehalten (nach meinem besten Wissen). Das Problem, das ich habe, ist, dass, wenn ich meine ST-Berechnung mehrmals ausführe, ich manchmal den Speicher für den Vektor herum zu halten scheint.Haskell: Undichte Speicher von ST/GC nicht sammeln?

Allocation Statistik:

5,435,386,768 bytes allocated in the heap 
    5,313,968 bytes copied during GC 
    134,364,780 bytes maximum residency (14 sample(s)) 
    3,160,340 bytes maximum slop 
      518 MB total memory in use (0 MB lost due to fragmentation) 

Hier nenne ich runST 20x mit unterschiedlichen Werten für meine Berechnung und einen 128MB-Vektor (wieder - nicht verwendet, nicht zurückgegeben oder außerhalb von ST bezeichnet). Die maximale Residenz sieht gut aus, im Grunde nur mein Vektor und ein paar MB anderer Dinge. Aber die Gesamtspeicherbelegung zeigt an, dass ich vier Kopien des Vektors gleichzeitig aktiv habe. Dies passt perfekt zur Größe des Vektors, für 256MB erhalten wir wie erwartet 1030MB.

Bei Verwendung eines 1-GB-Vektors ist nicht genügend Speicher vorhanden (4x1GB + Overhead> 32bit). Ich verstehe nicht, warum die RTS scheinbar unbenutzte, nicht referenzierte Erinnerung herumhält, anstatt sie nur zu verstehen, zumindest an dem Punkt, an dem eine Zuweisung andernfalls fehlschlagen würde.

Laufen mit + RTS -S ergibt folgendes Bild:

Alloc Copied  Live GC GC  TOT  TOT Page Flts 
    bytes  bytes  bytes user elap user elap 
134940616  13056 134353540 0.00 0.00 0.09 0.19 0 0 (Gen: 1) 
    583416  6756 134347504 0.00 0.00 0.09 0.19 0 0 (Gen: 0) 
    518020  17396 134349640 0.00 0.00 0.09 0.19 0 0 (Gen: 1) 
    521104  13032 134359988 0.00 0.00 0.09 0.19 0 0 (Gen: 0) 
    520972  1344 134360752 0.00 0.00 0.09 0.19 0 0 (Gen: 0) 
    521100  828 134360684 0.00 0.00 0.10 0.19 0 0 (Gen: 0) 
    520812  592 134360528 0.00 0.00 0.10 0.19 0 0 (Gen: 0) 
    520936  1344 134361324 0.00 0.00 0.10 0.19 0 0 (Gen: 0) 
    520788  1480 134361476 0.00 0.00 0.10 0.20 0 0 (Gen: 0) 
134438548  5964 268673908 0.00 0.00 0.19 0.38 0 0 (Gen: 0) 
    586300  3084 268667168 0.00 0.00 0.19 0.38 0 0 (Gen: 0) 
    517840  952 268666340 0.00 0.00 0.19 0.38 0 0 (Gen: 0) 
    520920  544 268666164 0.00 0.00 0.19 0.38 0 0 (Gen: 0) 
    520780  428 268666048 0.00 0.00 0.19 0.38 0 0 (Gen: 0) 
    520820  2908 268668524 0.00 0.00 0.19 0.38 0 0 (Gen: 0) 
    520732  1788 268668636 0.00 0.00 0.19 0.39 0 0 (Gen: 0) 
    521076  564 268668492 0.00 0.00 0.19 0.39 0 0 (Gen: 0) 
    520532  712 268668640 0.00 0.00 0.19 0.39 0 0 (Gen: 0) 
    520764  956 268668884 0.00 0.00 0.19 0.39 0 0 (Gen: 0) 
    520816  420 268668348 0.00 0.00 0.20 0.39 0 0 (Gen: 0) 
    520948  1332 268669260 0.00 0.00 0.20 0.39 0 0 (Gen: 0) 
    520784  616 268668544 0.00 0.00 0.20 0.39 0 0 (Gen: 0) 
    521416  836 268668764 0.00 0.00 0.20 0.39 0 0 (Gen: 0) 
    520488  1240 268669168 0.00 0.00 0.20 0.40 0 0 (Gen: 0) 
    520824  1608 268669536 0.00 0.00 0.20 0.40 0 0 (Gen: 0) 
    520688  1276 268669204 0.00 0.00 0.20 0.40 0 0 (Gen: 0) 
    520252  1332 268669260 0.00 0.00 0.20 0.40 0 0 (Gen: 0) 
    520672  1000 268668928 0.00 0.00 0.20 0.40 0 0 (Gen: 0) 
134553500  5640 402973292 0.00 0.00 0.29 0.58 0 0 (Gen: 0) 
    586776  2644 402966160 0.00 0.00 0.29 0.58 0 0 (Gen: 0) 
    518064  26784 134342772 0.00 0.00 0.29 0.58 0 0 (Gen: 1) 
    520828  3120 134343528 0.00 0.00 0.29 0.59 0 0 (Gen: 0) 
    521108  756 134342668 0.00 0.00 0.30 0.59 0 0 (Gen: 0) 

Hier scheint es, wir 'live Bytes' größer als ~ 128 MB haben.

Das +RTS -hy Profil im Grunde nur sagt, wir vergeben 128MB:

http://imageshack.us/a/img69/7765/45q8.png

Ich habe versucht, dieses Verhalten in einem einfacheren Programm wiedergibt, sondern auch mit den genauen Aufbau mit ST replizieren, einem Reader den Vektor enthält, gleiche Monad/Programmstruktur etc. Das einfache Testprogramm zeigt dies nicht. Durch die Vereinfachung meines großen Programms hört das Verhalten auch auf, wenn scheinbar völlig unabhängiger Code entfernt wird.

Qs:

  • Bin ich aus 20 wirklich um 4 mal diesen Vektor zu halten?
  • Wenn ja, wie sage ich eigentlich seit +RTS -Hy und maximum residency behaupte ich nicht, und was kann ich tun, um dieses Verhalten zu stoppen?
  • Wenn nein, warum ist Haskell nicht GC'ing und Adressraum/Speicher knapp, und was kann ich tun, um dieses Verhalten zu stoppen?

Vielen Dank!

+2

Speicher verwendet ist in der Regel zweimal die maximale Residenz oder mehr, hängt von der Zuordnung und Sammlung Muster. Der gesamte verwendete 518 MB Speicher ist also nicht alarmierend. Versuchen Sie GHC zu sagen, dass es nur so viel Speicher zu verwenden gibt, zum Beispiel $ ./foo + RTS-M256M, um es früher zu sammeln. Aber "es ist auch kein Verweis darauf außerhalb von runST" kann unwahr sein, Sie könnten tatsächlich ein Leck haben. Man müsste den Code sehen, wenn das der Fall ist. –

+0

@DanielFischer 518MB ist ~ 4x, obwohl. Würde der nicht speicherbare Absturz mit einem 1-GB-Vektor anzeigen, dass GHC * den Speicher nicht sammeln kann? + RTS -M256M schlägt mit "Heap erschöpft" fehl. Der Vektor wird erstellt, in eine Reader-Umgebung gestellt, das ist es. Sonst nichts, nicht sicher, was ich noch tun kann, um zu vermeiden, dass nach dem Verlassen von ST/Reader irgendwelche Referenzen verloren gehen. Wie ich schon sagte, ich kann dieses Problem nicht in einem einfacheren Programm reproduzieren. Es scheint eher zufällig zu sein. – NBFGRTW

+0

Nun, 4 × kann mit dem richtigen/falschen Zuweisungsmuster passieren. Der Out-of-memory-Absturz könnte darauf hindeuten, dass GHC nicht weiß, dass es jetzt gesammelt werden sollte, aber angesichts der Tatsache, dass "M256M" "Haufen erschöpft" verursacht, sieht es eher so aus, als ob etwas einen Bezug zum Biest hat. –

Antwort

2

Ich vermute, das ist ein Fehler in GHC und/oder der RTS.

Erstens bin ich zuversichtlich, dass es keine tatsächliche Leckage oder etwas ähnliches gibt.

Gründe:

  • Der Vektor wird nie überall eingesetzt. Nicht gelesen, nicht geschrieben, nicht referenziert. Es sollte gesammelt werden, sobald runST fertig ist. Selbst wenn die ST-Berechnung einen einzelnen Int zurückgibt, der sofort ausgedruckt wird, um ihn auszuwerten, ist das Speicherproblem immer noch vorhanden. Es gibt keinen Verweis auf diese Daten.
  • Jeder Profiling-Modus, den der RTS anbietet, ist in gewalttätiger Übereinstimmung, dass ich nie mehr als einen einzigen Vektor Speicher zugewiesen/referenziert habe. Jede Statistik und jedes hübsche Diagramm sagt das.

Nun, hier ist das interessante Bit. Wenn ich den GC manuell durch Aufruf von System.Mem.performGC nach jeder Ausführung meiner Funktion erzwinge, verschwindet das Problem vollständig.

So haben wir einen Fall, wo die Laufzeit GB Speicher hat, die (nachweisbar!) Kann von der GC zurückgewonnen werden und sogar nach eigener Statistik wird von niemandem mehr gehalten. Wenn der Speicherpool nicht mehr ausreicht, wird die Laufzeit nicht erfasst, sondern das Betriebssystem wird um mehr Speicher gebeten. Und selbst wenn dies schließlich fehlschlägt, sammelt sich die Laufzeit noch nicht (wodurch nachweislich GB-Speicher zurückgewonnen wird), sondern entscheidet sich stattdessen dafür, das Programm mit einem Speichermangel-Fehler zu beenden.

Ich bin kein Experte für Haskell, GHC oder GC. Aber das sieht mir schrecklich kaputt. Ich werde dies als Fehler melden.

+0

Haben Sie jemals zu bekommen melde dies? – jberryman