haskell memory-management garbage-collection ghc ghci

haskell - ¿Cómo puedo hacer que GHCI libere memoria?



memory-management garbage-collection (1)

La introducción

El siguiente código muestra que al usar runhaskell Haskell Garbage Collector libera la memoria, cuando a ya no se usa. Resulta en el volcado del núcleo mientras se libera la variable a , para un propósito, para inspeccionar el comportamiento, a tiene nullFunPtr como finalizador.

module Main where import Foreign.Ptr import Foreign.ForeignPtr main :: IO () main = do a <- newForeignPtr nullFunPtr nullPtr putStrLn "Hello World"

El problema

Al ejecutar lo mismo en ghci, no libera memoria. ¿Cómo puedo forzar a ghci a liberar variables ya no usadas?

$ ghci > import Foreign.Ptr > import Foreign.ForeignPtr > import System.Mem > a <- newForeignPtr nullFunPtr nullPtr > a <- return () -- rebinding variable a to show gc that I''m no longer using it > performGC > -- did not crash - GC didn''t release memory > ^D Leaving GHCi. [1] 4396 segmentation fault (core dumped) ghci

La memoria se lanzó al salir, pero ya es demasiado tarde para mí. Estoy extendiendo GHCi y usándolo para otro propósito y necesito liberar la memoria antes, a pedido o tan rápido como sea posible sería realmente genial.

Sé que puedo llamar a finalizeForeignPtr , pero estoy usando foreignPtr solo para depuración. ¿Cómo puedo liberar a en general en el último ejemplo?

Si no hay posibilidad de hacerlo con el indicador ghci, también puedo modificar el código ghci . Tal vez pueda lanzar esto mediante modyfing ghci Interactive Context o DynFlags ? Hasta ahora no he tenido suerte con mi reaserch.


Rastreando a través del código encontramos que el valor se almacena en el campo closure_env del tipo de datos PersistentLinkerState , que es un ClosureEnv , es decir, un mapeo de nombre a HValue s. La función relevante en Linker.hs es

extendLinkEnv :: [(Name,HValue)] -> IO () -- Automatically discards shadowed bindings extendLinkEnv new_bindings = modifyPLS_ $ /pls -> let new_closure_env = extendClosureEnv (closure_env pls) new_bindings in return pls{ closure_env = new_closure_env }

y aunque el comentario indica que debe eliminar el enlace oculto, no lo hace, al menos no de la manera que usted desea.

La razón es que, como AndrewC escribe correctamente: aunque ambas variables tienen el mismo nombre de código fuente, son diferentes al compilador (tienen un Unique adjunto). Podemos observar esto luego de agregar algún rastreo a la función anterior:

*GHCiGC> a <- newForeignPtr nullFunPtr nullPtr extendLinkEnv [a_azp] *GHCiGC> a <- return () extendLinkEnv [a_aF0] *GHCiGC> performGC extendLinkEnv [it_aFL]

Eliminar enlaces con el mismo nombre-fuente en este punto debería resolver su problema GC, pero no conozco el compilador lo suficiente como para decir qué más podría romperse. Le sugiero que abra un boleto, con suerte alguien lo sabrá.

Confusión en unión vs. valor

En los comentarios, parece haber cierta confusión sobre enlaces y valores. Considera este código:

> a <- return something > b <- return somethingelse > a <- return (b+b) > b <- return anewthing

Con la implementación actual, el montón consistirá en `

  • something
  • somethingelse
  • un thunk haciendo referencia al operador (+) y somethingelse malo
  • anewthing

Además, el entorno del intérprete tiene referencias a los cuatro valores del montón, por lo que no se puede hacer GC.

Lo que remdezx correctamente esperaba es que GHCi soltara la referencia a something y somethingelse . Esto, a su vez, permitiría que el sistema de tiempo de ejecución recoja something (no asumimos más referencias). GHCi todavía hace referencia al thunk, que a su vez hace referencia a somethingelse así, por lo que no sería basura.

Claramente, la pregunta fue muy específica para la implementación, y esta es la respuesta :-)