2012-05-09 9 views
10

Come i documenti della biblioteca dicono che CString creato con newCString deve essere liberato con la funzione free. Mi aspettavo che quando è stato creato CString ci sarebbe voluto un po 'di memoria e quando è stato rilasciato con free l'utilizzo della memoria sarebbe andato giù, ma non è così! Ecco codice di esempio:Liberare memoria allocata con newCString

module Main where 

import Foreign 
import Foreign.C.String 
import System.IO 

wait = do 
    putStr "Press enter" >> hFlush stdout 
    _ <- getLine 
    return() 

main = do 
    let s = concat $ replicate 1000000 ['0'..'9'] 
    cs <- newCString s 
    cs `seq` wait -- (1) 

    free cs 
    wait -- (2) 

Quando il programma si fermò a (1), htop programma ha dimostrato che l'utilizzo della memoria è da qualche parte intorno a 410M - questo è OK. Premo invio e il programma si ferma alla riga (2), ma l'utilizzo della memoria è ancora 410M nonostante sia stato free d!

Com'è possibile? Programma simile scritto in C si comporta come dovrebbe. Cosa mi manca qui?

+1

Quale versione di GHC stai utilizzando? La possibilità di restituire memoria al sistema operativo è stata aggiunta a GHC solo l'anno scorso. –

+0

'ghc --version' restituisce' The Glorious Glasgow Haskell Compilation System, versione 7.4.1' –

risposta

8

Il problema è che free indica al garbage collector che ora può raccogliere la stringa. Questo in realtà non costringe il garbage collector a funzionare, ma indica che CString è ora inutile. È ancora compito del GC decidere quando eseguire, in base all'euristica della pressione heap.

Puoi forza un'importante collezione chiamando performGC subito dopo la chiamata a free, che riduce immediatamente la memoria di 5M o giù di lì.

E.g. questo programma:

import Foreign 
import Foreign.C.String 
import System.IO 
import System.Mem 

wait = do 
    putStr "Press enter" >> hFlush stdout 
    _ <- getLine 
    return() 

main = do 
    let s = concat $ replicate 1000000 ['0'..'9'] 
    cs <- newCString s 
    cs `seq` wait -- (1) 

    free cs 
    performGC 
    wait -- (2) 

si comporta come previsto, con il seguente profilo di memoria - il primo punto rosso è la chiamata alla performGC, immediatamente deallocando la stringa. Il programma quindi si aggira intorno a 5 M fino alla sua cessazione.

enter image description here

+0

Grazie mille. Non sapevo che 'malloc' /' free' in ghc funzionasse in questo modo. Ho provato 'performGC' e funziona davvero. Bene, questa domanda è emersa quando stavo testando quanto bene funzionano i miei legami con certe librerie C. Li ho testati con una grande quantità di stringhe C e sono stato sorpreso di scoprire che la memoria non si stava liberando. Sembra che questo mistero sia risolto ora) –

+2

Immagino di non poter discutere con la tua prova che 'performGC' funziona davvero, ma questo è quello che presumo fosse la risposta fino a quando non sono andato a guardare [fonte] (http: // hackage.haskell.org/packages/archive/base/4.5.0.0/doc/html/src/Foreign-Marshal-Alloc.html#free) - mi sembra come 'free' chiama veramente la funzione C' libera () '. Come interagisce con il GC? –

+2

Sospetto che lo sia perché la memoria non è stata effettivamente rilasciata al sistema operativo dal pool di GHC rts finché non viene eseguito il GC. Quindi saresti in grado di riutilizzare il blocco di memoria di Haskell, ma non è ancora restituito al sistema operativo. –