2010-07-15 3 views
113

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

В общем случае, если требования к памяти типов 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 

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

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

ответ

145

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

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

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

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

data Uno = Uno a 
data Due = Due a b 

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

Тип 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 слова, но большое целое число принимает переменное количество пространства в зависимости от его стоимости. A ByteArray# принимает 2 слова (заголовок + размер) плюс пространство для самого массива.

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

Подробнее в The Layout of Heap Objects in the GHC Commentary.

+1

Спасибо, Саймон. Это именно то, что я хотел знать. – sastanin

+1

Разве это не заголовок два слова? Один для тега и один для указателя пересылки для использования во время GC или оценки? Разве это не добавит вам одного слова? –

+0

Пропорционально его значению или пропорционально его логарифму? – solidsnack

3

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

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

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

Также см. How to find out GHC's memory representations of data types? и How can I determine size of a type in Haskell?.

Смежные вопросы