2010-07-15 91 views
113

如何查找在Haskell中存儲某些數據類型值所需的實際內存量(主要是使用GHC)?是否可以在運行時對其進行評估(例如,在GHCi中)還是可以從組件中估計組合數據類型的內存需求?Haskell數據類型的內存佔用情況

在一般情況下,如果類型ab內存的要求是已知的,什麼是代數數據類型,如內存開銷:

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大小與值的大小無關)。問題是,在數據類型的情況下,完全評估時它的值需要多少內存?

我發現GHCi中有一個:set +s選項來查看內存統計信息,但不清楚如何估計單個值的內存佔用情況。

回答

145

(以下適用於GHC,其他的編譯器可使用不同的存儲約定)拇指

規則:構造成本的報頭一個字,並且對於每個字段一個字。例外:沒有字段的構造函數(如NothingTrue)不佔用空間,因爲GHC會創建這些構造函數的單個實例並在所有用途中共享它。

一個字在32位機器上是4個字節,在64位機器上是8個字節。

因此,例如,

data Uno = Uno a 
data Due = Due a b 

一個Uno取2個字,和一個Due花費3.

Int類型被定義爲

data Int = I# Int# 

現在,Int#需要一個字,所以Int總共需要2。大多數unboxed類型需要一個單詞,例外是Int64#,Word64#Double#(在32位機器上),這取2個.GHC實際上有一個小型值緩存,類型爲IntChar,所以在很多情況下,這些緩存不會堆積空間。 A String只需要列表單元格的空間,除非您使用Char s> 255。

Int8Int具有相同的表示形式。 Integer的定義如下:

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

所以小IntegerS#)取2個字,但根據其值大的整數取的空間中的變量數量。 A ByteArray#需要2個字(標題+大小)加上陣列本身的空間。

請注意,newtype定義的構造函數是免費的newtype純粹是一個編譯時的想法,它在運行時不佔用空間並且不需要任何指令。

更多詳細信息在The Layout of Heap Objects in the GHC Commentary

+1

謝謝,西蒙。這正是我想知道的。 – sastanin 2010-07-15 15:19:26

+1

是不是頭兩個字?一個用於標記,另一個用於GC或評估期間使用的轉發指針?那麼這不會爲你的總數增加一個詞嗎? – 2010-07-15 17:11:11

+0

與它的值成正比或與其對數成正比嗎? – solidsnack 2010-07-15 17:25:33