IORef 的内存占用和性能
Memory footprint and performance of IORef
如果我知道 a 的大小是 x,我想知道来自类型 IORef a 的变量的内存占用量是多少。
另外,应用于整数的函数 writeIORef 的预期性能与说 Java 中的常规变量赋值(如 x = 3)相比的预期性能是多少?
在 Haskell 中,IORef a
的行为类似于 single-element 可变数组。 IORef
的 definition 如下,忽略新类型包装:
data IORef a = IORef (MutVar# RealWorld a)
这里,MutVar# RealWorld a
是原始可变引用类型。它是一个指向两个字的指针,一个header,以及一个有效载荷,它本身就是一个指向正常提升的Haskell object的指针。因此 MutVar
的开销是两个字(在 64 位系统上为 16 字节)和一个间接寻址。
因此 MutVar#
的开销是一个额外的间接寻址和一个额外的 header 字。这是不可避免的。相比之下,IORef
构造函数的开销也是一个header字和一个间接寻址,但是可以通过解包来消除IORef
:
data Foo a = Foo !(IORef a) a a
在这里,IORef
上的 bang 导致基础 MutVar
被解包到 Foo
。但是,当我们定义新的数据类型时,这种解包工作,但如果我们使用任何现有的参数化类型,如列表,它就不起作用。在 [IORef a]
中,我们通过两次额外的间接访问来支付全部费用。
IORef
如果用作函数的参数,通常也会被 GHC 优化解包:如果使用优化进行编译,IORef a -> b
通常会被解包为 MutVar# RealWorld a -> b
.
但是,当您使用大量 IORef
-s 时,上述所有开销都没有 garbage collection 中的开销重要。为避免这种情况,建议使用单个可变数组而不是许多 IORef
-s.
如果我知道 a 的大小是 x,我想知道来自类型 IORef a 的变量的内存占用量是多少。 另外,应用于整数的函数 writeIORef 的预期性能与说 Java 中的常规变量赋值(如 x = 3)相比的预期性能是多少?
在 Haskell 中,IORef a
的行为类似于 single-element 可变数组。 IORef
的 definition 如下,忽略新类型包装:
data IORef a = IORef (MutVar# RealWorld a)
这里,MutVar# RealWorld a
是原始可变引用类型。它是一个指向两个字的指针,一个header,以及一个有效载荷,它本身就是一个指向正常提升的Haskell object的指针。因此 MutVar
的开销是两个字(在 64 位系统上为 16 字节)和一个间接寻址。
因此 MutVar#
的开销是一个额外的间接寻址和一个额外的 header 字。这是不可避免的。相比之下,IORef
构造函数的开销也是一个header字和一个间接寻址,但是可以通过解包来消除IORef
:
data Foo a = Foo !(IORef a) a a
在这里,IORef
上的 bang 导致基础 MutVar
被解包到 Foo
。但是,当我们定义新的数据类型时,这种解包工作,但如果我们使用任何现有的参数化类型,如列表,它就不起作用。在 [IORef a]
中,我们通过两次额外的间接访问来支付全部费用。
IORef
如果用作函数的参数,通常也会被 GHC 优化解包:如果使用优化进行编译,IORef a -> b
通常会被解包为 MutVar# RealWorld a -> b
.
但是,当您使用大量 IORef
-s 时,上述所有开销都没有 garbage collection 中的开销重要。为避免这种情况,建议使用单个可变数组而不是许多 IORef
-s.