2013-08-16 4 views
6

Ho un calcolo all'interno di ST che alloca memoria attraverso un Data.Vector.Unboxed.Mutable. Il vettore non viene mai letto o scritto, né alcun riferimento a esso conservato al di fuori di runST (per quanto ne so io). Il problema che ho è che quando eseguo il mio calcolo ST più volte, a volte mi sembra di mantenere la memoria intorno al vettore.Haskell: perdita di memoria da parte di ST/GC non raccolta?

statistiche di allocazione:

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) 

Qui mi chiamano runST 20x con valori diversi per il mio calcolo e un vettore 128 MB (ancora una volta - non utilizzato, non restituiti o fa riferimento al di fuori di ST). La residenza massima sembra buona, in pratica solo il mio vettore più pochi MB di altre cose. Ma l'uso della memoria totale indica che ho quattro copie del vettore attivo allo stesso tempo. Questo si adatta perfettamente alla dimensione del vettore, per 256 MB otteniamo 1030 MB come previsto.

L'utilizzo di un vettore da 1 GB esaurisce la memoria (4x1 GB + sovraccarico> 32 bit). Non capisco perché l'RTS conservi la memoria apparentemente inutilizzata e non referenziata, invece di limitarsi a fare il GC, almeno nel punto in cui altrimenti l'allocazione fallirebbe.

Correndo con + RTS -S rivela quanto segue:

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) 

Qui sembra che abbiamo superiore a ~ 128MB 'byte live'.

Il profilo +RTS -hy fondamentalmente solo dice che noi destiniamo 128MB:

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

Ho provato riprodurre questo comportamento in un programma più semplice, ma anche con replicare la configurazione esatta con ST, un lettore che contiene il vettore, stesso monad/struttura del programma ecc. il semplice programma di test non lo mostra. Semplificando il mio grande programma, il comportamento si interrompe anche quando si rimuove il codice apparentemente completamente non correlato.

Qs:

  • Sono davvero mantenere questo vettore circa 4 volte su 20?
  • In caso affermativo, come faccio a sapere dal momento che +RTS -Hy e maximum residency affermano che non lo sono, e cosa posso fare per interrompere questo comportamento?
  • Se no, perché Haskell non sta eseguendo GC e sta esaurendo lo spazio degli indirizzi/memoria e cosa posso fare per fermare questo comportamento?

Grazie!

+2

La memoria utilizzata è in genere il doppio della residenza massima o più, dipende dall'assegnazione e dal modello di raccolta. Quindi la memoria totale da 518 MB utilizzata non è allarmante di per sé. Prova a dire a GHC che c'è solo tanta memoria da usare, ad esempio '$ ./foo + RTS -M256M', per forzarla a raccogliere prima. Ma "né alcun riferimento ad esso conservato al di fuori di runST" può essere falso, si potrebbe effettivamente avere una perdita. Uno dovrebbe vedere il codice se questo è il caso. –

+0

@DanielFischer 518MB è ~ 4x, però. L'arresto anomalo della memoria con un vettore da 1 GB indica che GHC * non può * raccogliere la memoria? + RTS -M256M fallisce con "Heap esaurito". Il vettore viene creato, inserito in un ambiente Reader, il gioco è fatto. Niente altro, non sono sicuro di cos'altro posso fare per evitare la perdita di riferimenti dopo aver lasciato ST/Reader. Come ho detto, non riesco a riprodurre questo problema in un programma più semplice. Sembra piuttosto casuale. – NBFGRTW

+0

Bene, 4 × può accadere dato il modello di allocazione giusto/sbagliato. L'arresto anomalo della memoria potrebbe indicare che GHC non sa che dovrebbe ora raccogliere, ma dato che '-M256M' causa" esaurimento dell'heap ", sembra più che qualcosa abbia un riferimento alla bestia dopo tutto. –

risposta

2

Sospetto che si tratti di un errore in GHC e/o nell'RTS.

In primo luogo, sono sicuro che non ci siano perdite di spazio o cose del genere.

Motivi:

  • Il vettore non viene mai utilizzato da nessuna parte. Non letto, non scritto, non referenziato. Dovrebbe essere raccolto una volta eseguito runST. Anche quando il calcolo ST restituisce un singolo Int che viene immediatamente stampato per valutarlo, il problema della memoria esiste ancora. Non c'è riferimento a quei dati.
  • Ogni modalità di profilatura offerta da RTS è in totale accordo che non ho mai avuto più di un singolo vettore di memoria allocata/referenziata. Ogni statistica e bella carta lo dice.

Ora, ecco il bit interessante. Se forzo manualmente il GC chiamando lo System.Mem.performGC dopo ogni esecuzione della mia funzione, il problema scompare completamente.

Quindi abbiamo un caso in cui il runtime ha GB di memoria che (in modo dimostrabile!) Può essere recuperato dal GC e anche in base alla propria statistica non è più detenuto da nessuno. Quando si esaurisce il pool di memoria, il runtime non viene raccolto, ma chiede al sistema operativo più memoria. E anche quando finalmente fallisce, il runtime continua a non raccogliere (che potrebbe recuperare GB di memoria, in modo dimostrabile), ma sceglie invece di terminare il programma con un errore di memoria esaurita.

Non sono esperto di Haskell, GHC o GC. Ma questo mi sembra terribilmente rotto. Lo segnalerò come un bug.

+0

Hai mai avuto segnalare questo? – jberryman