2012-05-09 14 views
10

Como los documentos de la biblioteca dicen CString creados con newCString deben liberarse con la función free. He estado esperando que cuando se crea CString se necesitaría algo de memoria y cuando se lance con free el uso de la memoria disminuirá, ¡pero no fue así! Aquí es código de ejemplo:Liberar memoria asignada 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) 

Cuando el programa se detuvo en (1), programa de htop mostró que el uso de memoria es de alrededor de 410M - esto está bien. Presiono enter y el programa se detiene en la línea (2), pero el uso de memoria sigue siendo 410M a pesar de que cs ha sido free d!

¿Cómo es esto posible? El programa similar escrito en C se comporta como debería. ¿Que me estoy perdiendo aqui?

+1

¿Qué versión de GHC estás utilizando? La capacidad de devolver memoria al sistema operativo solo se agregó a GHC el año pasado. –

+0

'ghc --version' outputs' The Glorious Glasgow Haskell Compilation System, versión 7.4.1' –

Respuesta

8

El problema es que free simplemente indica al recolector de basura que ahora puede recoger la cadena. Sin embargo, eso no obliga realmente al recolector de basura a ejecutarse, solo indica que el CString ahora es basura. Todavía le corresponde al GC decidir cuándo se ejecutará, en función de la heurística de presión del montón.

Puede fuerza una importante colección llamando performGC inmediatamente después de la llamada a free, lo que reduce inmediatamente a la memoria 5M o menos.

E.g. este programa:

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) 

comporta como se esperaba, con el siguiente perfil de memoria - el primer punto rojo es el llamado a performGC, cancelar la asignación de inmediato la cadena. El programa luego se desplaza alrededor de 5M hasta que se termina.

enter image description here

+0

Muchas gracias. No sabía que 'malloc' /' free' en ghc funciona de esta manera. Intenté 'performGC' y de hecho funciona. Bueno, esta pregunta surgió cuando estaba probando qué tan bien funcionan mis enlaces a cierta biblioteca C. Los probé con una gran cantidad de cadenas C y me sorprendí al descubrir que la memoria no se estaba liberando. Parece que este misterio está resuelto ahora) –

+2

Supongo que no puedo discutir con su evidencia de que 'performGC' realmente funciona, pero esto es lo que asumí fue la respuesta hasta que fui y miré la [fuente] (http: // hackage.haskell.org/packages/archive/base/4.5.0.0/doc/html/src/Foreign-Marshal-Alloc.html#free) - me parece que 'free' realmente llama a la función C' libre () '. ¿Cómo interactúa eso con el GC? –

+2

Sospecho que se debe a que la memoria no se libera realmente en el sistema operativo desde el grupo de rts GHC hasta que se ejecuta el GC. Entonces, podrías volver a utilizar el bloque de memoria de Haskell, pero aún no se ha devuelto al sistema operativo. –

Cuestiones relacionadas