gpt4 book ai didi

haskell - 为什么严格标志会使内存使用量增加?

转载 作者:行者123 更新时间:2023-12-03 15:07:08 25 4
gpt4 key购买 nike

以下两个程序仅通过变量 st 上的严格标志不同

$ 猫 testStrictL.hs

module Main (main) where

import qualified Data.Vector as V
import qualified Data.Vector.Generic as GV
import qualified Data.Vector.Mutable as MV

len = 5000000

testL = do
mv <- MV.new len
let go i = do
if i >= len then return () else
do let st = show (i+10000000) -- no strictness flag
MV.write mv i st
go (i+1)
go 0
v <- GV.unsafeFreeze mv :: IO (V.Vector String)
return v

main =
do
v <- testL
print (V.length v)
mapM_ print $ V.toList $ V.slice 4000000 5 v

$ 猫 testStrictS.hs
module Main (main) where

import qualified Data.Vector as V
import qualified Data.Vector.Generic as GV
import qualified Data.Vector.Mutable as MV

len = 5000000

testS = do
mv <- MV.new len
let go i = do
if i >= len then return () else
do let !st = show (i+10000000) -- this has the strictness flag
MV.write mv i st
go (i+1)
go 0
v <- GV.unsafeFreeze mv :: IO (V.Vector String)
return v

main =
do
v <- testS
print (V.length v)
mapM_ print $ V.toList $ V.slice 4000000 5 v

使用 ghc 7.03 在 Ubuntu 10.10 上编译和运行这两个程序
我得到以下结果

$ ghc --make testStrictL.hs -O3 -rtsopts
[2 之 2] 编译主要 ( testStrictL.hs, testStrictL.o )
链接 testStrictL ...
$ ghc --make testStrictS.hs -O3 -rtsopts
[2 of 2] 编译主程序 ( testStrictS.hs, testStrictS.o )
链接 testStrictS ...
$ ./testStrictS +RTS -sstderr
./testStrictS +RTS -sstderr
500万
“14000000”
“14000001”
“14000002”
“14000003”
“14000004”
在堆中分配了 824,145,164 字节
GC 期间复制了 1,531,590,312 个字节
349,989,148 字节最大驻留(6 个样本)
1,464,492 字节最大斜率
656 MB 总内存正在使用(0 MB 由于碎片丢失)

第 0 代:1526 次收集,0 次并行,5.96 秒,6.04 秒过去
第 1 代:6 次收集,0 次并行,2.79 秒,4.36 秒过去

初始化时间 0.00s(经过 0.00s)
MUT时间1.77s(经过2.64s)
GC 时间 8.76s(经过 10.40s)
退出时间 0.00s(经过 0.13s)
总时间 10.52s(经过 13.04s)

%GC 时间 83.2%(经过 79.8%)

分配速率 466,113,027 字节/MUT 秒

生产力占总用户的 16.8%,占总使用时间的 13.6%

$ ./testStrictL +RTS -sstderr
./testStrictL +RTS -sstderr
500万
“14000000”
“14000001”
“14000002”
“14000003”
“14000004”
在堆中分配了 81,091,372 字节
GC 期间复制了 143,799,376 个字节
44,653,636 字节最大驻留(3 个样本)
1,005,516 字节最大斜率
79 MB 正在使用的总内存(0 MB 由于碎片丢失)

第 0 代:112 次收集,0 次并行,0.54 秒,0.59 秒过去
第 1 代:3 次收集,0 次并行,0.41s,0.45s 已过

初始化时间 0.00s(经过 0.03s)
MUT 时间 0.12s(经过 0.18s)
GC时间0.95s(经过1.04s)
退出时间 0.00s(经过 0.06s)
总时间 1.06s(经过 1.24s)

%GC 时间 89.1%(经过 83.3%)

分配速率 699,015,343 字节/MUT 秒

生产力占总用户的 10.9%,占总使用时间的 9.3%

有人可以解释为什么严格标志似乎导致程序使用这么多
内存?这个简单的例子来自我试图理解为什么我的程序
在读取 500 万行的大文件和创建向量时使用这么多内存
的记录。

最佳答案

这里的问题主要是您使用的是 String (它是 [Char] 的别名)类型,由于其表示为单个 Char 的非严格列表s 要求内存堆上每个字符 5 个字(另见 this blog article 以了解一些内存占用比较)

在惰性情况下,您基本上存储了指向(共享)评估函数 show . (+10000000) 的未评估 thunk和一个变化的整数,而在严格的情况下,由 8 个字符组成的完整字符串似乎被物化了(通常 bang 模式只会强制最外面的列表构造函数 : ,即惰性 String 的第一个字符,待评估),这需要更多的堆空间,字符串越长。

存储 5000000 String因此,长度为 8 的类型字符串需要 5000000*8*5 = 200000000 个字,这在 32 位上对应于约 763 MiB。如果 Char数字是共享的,您只需要其中的 3/5,即 ~458 MiB,这似乎与您观察到的内存开销相匹配。

如果您更换 String通过更紧凑的东西,例如 Data.ByteString.ByteString您会注意到,与使用普通 String 相比,内存开销将降低大约一个数量级。 .

关于haskell - 为什么严格标志会使内存使用量增加?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6893877/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com