Объем памяти типов данных Haskell


как я могу найти фактический объем памяти, необходимый для хранения значения некоторого типа данных в 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 не связан с размером значения). Вопрос в том, учитывая тип данных, сколько памяти занимает его значение при полной оценке?

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

2 116

2 ответа:

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

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

слово составляет 4 байта на 32-разрядной машине и 8 байт на 64-разрядной машина.

так, например,

data Uno = Uno a
data Due = Due a b

an Uno принимает 2 слова, и Due занимает 3.

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

data Int = I# Int#

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

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

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

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

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

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

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

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

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

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