Объем памяти типов данных 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
option in GHCi to see memory stats, but it is not clear how to estimate the memory footprint of a single value.
2 ответа
(Следующее относится к 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 слова, но большое целое занимает переменное количество места в зависимости от его значения. ByteArray#
занимает 2 слова (заголовок + размер) плюс место для самого массива.
Обратите внимание, что конструктор определен с newtype
бесплатно newtype
это просто идея времени компиляции, и она не занимает места и не требует никаких инструкций во время выполнения.
Больше деталей в Макете объектов кучи в комментарии GHC.
Пакет ghc-datasize предоставляет функцию recursiveSize для вычисления размера объекта GHC. Тем не мение...
Сборка мусора выполняется до вычисления размера, потому что сборщик мусора затруднит обход кучи.
... так что было бы непрактично называть это часто!
Также см. Как узнать представления памяти типов данных в GHC? и как я могу определить размер шрифта в Haskell?,