Слід пам'яті типів даних Haskell


124

Як я можу знайти фактичний об'єм пам'яті, необхідний для зберігання значення певного типу даних у 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

Я розумію, що фактичне розподілення пам’яті вище через затримку збору сміття. Це може суттєво відрізнятися через ледачу оцінку (і розмір грона не пов'язаний з величиною значення). Питання полягає в тому, з урахуванням типу даних, скільки пам'яті займає її значення при повному оцінці?

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

Відповіді:


156

(Далі стосується GHC, інші компілятори можуть використовувати різні умови зберігання)

Правило: великий конструктор коштує одне слово для заголовка та одне слово для кожного поля . Виняток: конструктор без полів (як-от Nothingабо True) не займає місця, оскільки GHC створює єдиний екземпляр цих конструкторів і ділиться ним між усіма напрямами.

Слово - 4 байти на 32-бітній машині та 8 байтів на 64-бітній машині.

Так, наприклад

data Uno = Uno a
data Due = Due a b

an Unoзаймає 2 слова, а a 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 слова, але велике ціле число займає змінну кількість простору залежно від його значення. A ByteArray#займає 2 слова (заголовок + розмір) плюс пробіл для самого масиву.

Зауважте, що конструктор, визначений з newtype, вільний . newtypeЦе суто ідея часу компіляції, і вона не займає місця і не вимагає інструкцій під час виконання.

Більш детально у «Макет об’єктів купи» в коментарі GHC .


1
Дякую, Саймоне. Це саме те, що я хотів знати.
зустріч

2
Це не заголовок двох слів? Один для тегу, а інший для вказівника переадресації для використання під час GC чи оцінки? Так чи не додало б це слово до вашої загальної суми?
Едвард КМЕТТ

5
@Edward: Блискавки перезаписані непрямими (які пізніше видаляються GC), але це лише 2 слова, і кожен купі об'єкт гарантовано має розміром щонайменше два 2 слова. Без будь-яких функцій профілювання та налагодження увімкнений заголовок справді лише одне слово. У GHC, тобто в інших реалізаціях, все може бути інакше.
nominolo

3
nominolo: так, але від Closure.h: / * Thunk має слово прокладки, щоб прийняти оновлене значення. Це так, що оновлення не замінює корисну навантаження, тож ми можемо уникати необхідності блокувати об'єм під час входу та оновлення. Примітка. Це не стосується THUNK_STATIC, які не мають корисного навантаження. Примітка. Ми залишаємо це слово прокладок всіма способами, а не лише SMP, щоб нам не довелося перекомпілювати всі наші бібліотеки для SMP. * / Корисне навантаження не перезаписується під час непрямості. Індирекція записується в окремому місці в заголовку.
Едвард КМЕТТ

6
Так, але зауважте, це лише для грона . Це не стосується конструкторів. Оцінити розмір грона все-таки трохи складно - вам доведеться порахувати вільні змінні.
nominolo

4

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

Збір сміття проводиться перед розрахунком розміру, тому що сміттєзбірник утрудняє купу прогулянок.

... тож не було б практично так називати це часто!

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.