haskell memory-management ghc algebraic-data-types

Huella de memoria de los tipos de datos Haskell



memory-management ghc (2)

¿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?

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

data Uno = Uno a data Due = Due a b

Por ejemplo, ¿cuántos bytes en memoria 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 real de memoria 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.


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

Regla de oro: 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 instancia única 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.

Por ejemplo,

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, por lo que Int toma 2 en total. La mayoría de los tipos no compartidos 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 pequeños valores de tipo Int y Char , por lo que en muchos casos no tomar espacio de montón en absoluto. Una 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 Integer pequeño ( S# ) toma 2 palabras, pero un entero grande toma una cantidad variable de espacio dependiendo 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 gratuito . newtype es puramente una idea en tiempo de compilación, no ocupa espacio y no cuesta instrucciones en tiempo de ejecución.

Más detalles en The Layout of Heap Objects en el comentario de GHC .