我如何找到在Haskell中存储某种数据类型的值所需的实际内存量(主要是GHC)?是否可以在运行时对其进行评估(例如在GHCi中),或者可以从其组件中估算复合数据类型的内存需求?

通常,如果知道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选项可以查看内存统计信息,但是目前尚不清楚如何估算单个值的内存占用量。

最佳答案

(以下内容适用于GHC,其他编译器可能使用不同的存储约定)

经验法则:构造函数的 header 花费一个词,每个字段花费一个词。异常(exception):没有字段的构造函数(例如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个单词。大部分未装箱的类型都占用一个单词,异常(exception)是Int64#Word64#Double#(在32位计算机上),它们占用2。GHC实际上具有小类型IntChar类型的小值的缓存,因此在许多情况下,这些不占用堆空间完全没有空间。除非您使用String> 255,否则Char仅需要用于列表单元格的空间。
Int8具有与Int相同的表示。 Integer的定义如下:
data Integer
  = S# Int#                            -- small integers
  | J# Int# ByteArray#                 -- large integers

因此,一个小的Integer(S#)占用2个字,但是一个大的整数根据其值占用可变的空间量。 ByteArray#占用2个字(标题+大小)加上数组本身的空间。

请注意,newtype定义的构造函数是免费的newtype纯粹是一个编译时想法,它不占用空间,并且在运行时不花费任何指令。

The Layout of Heap Objects in the GHC Commentary中有更多详细信息。

关于haskell - Haskell数据类型的内存占用量,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/3254758/

10-09 15:53