2010-07-15 25 views
113

¿Cómo puedo encontrar la cantidad real de memoria requerida para almacenar un valor de algún tipo de datos en Haskell (principalmente con GHC)? ¿Es posible evaluarlo en tiempo de ejecución (por ejemplo, en GHCi) o es posible estimar los requisitos de memoria de un tipo de datos compuesto a partir de sus componentes?Huella de memoria de los tipos de datos Haskell

En general, si se conocen los requisitos de memoria de tipos a y b, ¿cuál es la sobrecarga de memoria de tipos de datos algebraicos tales como:

data Uno = Uno a 
data Due = Due a b 

Por ejemplo, el número de bytes en la memoria no ocupan estos valores?

1 :: Int8 
1 :: Integer 
2^100 :: Integer 
\x -> x + 1 
(1 :: Int8, 2 :: Int8) 
[1] :: [Int8] 
Just (1 :: Int8) 
Nothing 

Entiendo que la asignación de la memoria real es mayor debido a la recolección diferida de basura. Puede ser significativamente diferente debido a la evaluación diferida (y el tamaño del procesador no está relacionado con el tamaño del valor). La pregunta es, dado un tipo de datos, ¿cuánta memoria tiene su valor cuando se evalúa por completo?

Encontré que hay una opción :set +s en GHCi para ver las estadísticas de memoria, pero no está claro cómo estimar la huella de memoria de un solo valor.

Respuesta

145

(Lo siguiente se aplica a GHC, otros compiladores pueden utilizar diferentes convenciones de almacenamiento)

Regla de oro: un constructor cuesta una palabra por una cabecera y una palabra para cada campo. Excepción: un constructor sin campos (como Nothing o True) no ocupa espacio, porque GHC crea una única instancia de estos constructores y la comparte entre todos los usos.

Una palabra tiene 4 bytes en una máquina de 32 bits y 8 bytes en una máquina de 64 bits.

Así, por ejemplo,

data Uno = Uno a 
data Due = Due a b 

un Uno tarda 2 palabras, y una Due toma 3.

El tipo Int se define como

data Int = I# Int# 

ahora, Int# toma una palabra, por lo Int toma 2 en total. La mayoría de los tipos sin clasificar toman una palabra, excepto Int64#, Word64# y Double# (en una máquina de 32 bits) que toman 2. GHC en realidad tiene una memoria caché de valores pequeños de tipo Int y Char, por lo que en muchos casos estos no son un montón espacio en absoluto. Un String solamente requiere espacio para las celdas de la lista, a menos que utilice Char s> 255.

Un Int8 tiene representación idéntica a Int. Integer se define así:

data Integer 
    = S# Int#       -- small integers 
    | J# Int# ByteArray#     -- large integers 

lo que una pequeña Integer (S#) tarda 2 palabras, pero un gran número entero toma una cantidad variable de espacio en función de su valor. Un ByteArray# toma 2 palabras (encabezado + tamaño) más espacio para la matriz en sí.

Tenga en cuenta que un constructor definido con newtype es gratis. newtype es una idea puramente de compilación, no ocupa espacio y no cuesta instrucciones en tiempo de ejecución.

Más detalles en The Layout of Heap Objects in the GHC Commentary.

+1

Gracias, Simon. Esto es exactamente lo que quería saber. – sastanin

+1

¿No es el encabezado dos palabras? Uno para la etiqueta, y otro para el puntero de reenvío para usar durante GC o evaluación? Entonces, ¿no agregaría eso una palabra a tu total? –

+0

¿Proporcional a su valor o proporcional al logaritmo del mismo? – solidsnack

Cuestiones relacionadas