Объем потребляемой памяти типов данных 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

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

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

120
задан Boann 3 March 2017 в 23:48
поделиться

1 ответ

(Нижеследующее относится к 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 требует места только для ячеек списка, если вы не используете Chars > 255.

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

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

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

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

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

153
ответ дан 24 November 2019 в 01:41
поделиться
Другие вопросы по тегам:

Похожие вопросы: