Huella de memoria de los tipos de datos de Haskell


¿Cómo puedo encontrar la cantidad real de memoria necesaria 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?

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

data Uno = Uno a
data Due = Due a b

Por ejemplo, cuántos bytes en memoria hacen estos valores ocupar?

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 real de memoria es mayor debido al retraso en la recolección de basura. Puede ser significativamente diferente debido a la evaluación perezosa (y el tamaño de tonk no está relacionado con el tamaño del valor). La pregunta es, dado un tipo de datos, ¿cuánta memoria toma su valor cuando se evalúa completamente?

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.

Author: Boann, 2010-07-15

2 answers

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

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

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

Así por ejemplo, la

data Uno = Uno a
data Due = Due a b

Un Uno toma 2 palabras, y un Due toma 3.

El tipo Int se define como

data Int = I# Int#

Ahora, Int# toma una palabra, así que Int toma 2 en total. La mayoría de los tipos sin caja toman una palabra, las excepciones son Int64#, Word64#, y Double# (en una máquina de 32 bits) que toman 2. GHC en realidad tiene una caché de valores pequeños de tipo Int y Char, por lo que en muchos casos estos no ocupan espacio en el montón en absoluto. A String solo requiere espacio para las celdas de la lista, a menos que use Char s > 255.

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

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

Así que un pequeño Integer (S#) toma 2 palabras, pero un entero grande toma una cantidad variable de espacio dependiendo de su valor. A 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 libre. newtype es puramente una idea en tiempo de compilación, y no ocupa espacio y no cuesta instrucciones en ejecución tiempo.

Más detalles en La Disposición de los Objetos Heap en el Comentario GHC.

 150
Author: Simon Marlow,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-07-16 08:11:21

El paquete ghc-datasize proporciona la función recursiveSize para calcular el tamaño de un objeto GHC. Obstante...

Se realiza una recolección de basura antes de calcular el tamaño, porque el recolector de basura dificultaría los paseos en montones.

{así que no sería práctico llamar a esto a menudo!

Véase también ¿Cómo averiguar las representaciones de memoria de GHC de los tipos de datos? y ¿Cómo puedo determinar el tamaño de un tipo en Haskell?.

 4
Author: mhwombat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:10:26