Объем памяти типов данных Haskell - PullRequest
119 голосов
/ 15 июля 2010

Как узнать фактический объем памяти, необходимый для хранения значения некоторого типа данных в Haskell (в основном с GHC)? Можно ли оценить его во время выполнения (например, в GHCi) или можно оценить требования к памяти составного типа данных по его компонентам?

В общем случае, если известны требования к памяти типов a и b, каковы затраты памяти на алгебраические типы данных, такие как:

data Uno = Uno a
data Due = Due a b

Например, сколько байтов в памяти занимают эти значения?

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

Я понимаю, что фактическое выделение памяти выше из-за отложенного сбора мусора. Это может значительно отличаться из-за ленивой оценки (и размер thunk не связан с размером значения). Вопрос, учитывая тип данных, сколько памяти занимает его значение при полной оценке?

Я обнаружил, что в GHCi есть опция :set +s для просмотра статистики памяти, но не ясно, как оценить объем памяти одного значения.

Ответы [ 2 ]

153 голосов
/ 15 июля 2010

(следующее относится к GHC, другие компиляторы могут использовать другие соглашения о хранении)

Практическое правило: конструктор стоит одно слово для заголовка и одно слово для каждого поля .Исключение: конструктор без полей (например, Nothing или True) не занимает места, потому что GHC создает один экземпляр этих конструкторов и разделяет его среди всех применений.

Слово составляет 4 байта на32-разрядный компьютер и 8 байт на 64-разрядном компьютере.

Например,

data Uno = Uno a
data Due = Due a b

Uno занимает 2 слова, а Due - 3 *. 1016*

Тип Int теперь определяется как

data Int = I# Int#

, Int# занимает одно слово, поэтому Int - 2.Большинство распакованных типов принимают одно слово, за исключением Int64#, Word64# и Double# (на 32-разрядной машине), которые занимают 2. GHC на самом деле имеет кэш малых значений типа Int и Char, поэтому во многих случаях они вообще не занимают места в куче.Для String требуется только место для ячеек списка, если вы не используете Char s> 255.

Int8 имеет идентичное представление Int.Integer определяется следующим образом:

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

, поэтому небольшое Integer (S#) занимает 2 слова, а большое целое занимает переменное количество места в зависимости от его значения.ByteArray# занимает 2 слова (заголовок + размер) плюс пробел для самого массива.

Обратите внимание, что конструктор, определенный с помощью newtype, свободен .newtype это просто идея времени компиляции, и она не занимает места и не требует никаких инструкций во время выполнения.

Подробнее в Расположение объектов кучи в комментарии GHC .

4 голосов
/ 21 сентября 2015

Пакет ghc-datasize предоставляет функцию recursiveSize для вычисления размера объекта GHC. Однако ...

Сборка мусора выполняется до вычисления размера, потому что сборщик мусора затруднит прогулки в куче.

... так что было бы непрактично называть это часто!

Также см. Как узнать представления памяти типов данных в GHC? и Как определить размер типа в Haskell? .

...