我正在对Binary
个对象进行Text
序列化和反序列化,我注意到未解码的thunk使用多的内存比实际长度更多数据。我创建了一个可以重现问题的玩具程序(有关完整设置,请参阅this gist):
import qualified Data.ByteString.Lazy as B
import qualified Data.Text as T
main = do
handle <- openBinaryFile "testfile" ReadMode
initSize <- hFileSize handle
str <- B.hGet handle (fromInteger initSize)
hClose handle
--msgs :: [T.Text]
let (_, msgs) = decodeMany str
--here we fool the GC into retaining the thunks in msgs
chr <- readLn
print $ map (max chr) $ map (T.foldl1 max) msgs
--now we let it collect them
num1 <- readLn
print (num1 + 1)
当我运行它时:
$ ./Test2 +RTS -S
Alloc Copied Live GC GC TOT TOT Page Flts
bytes bytes bytes user elap user elap
108112 6936 82320 0.00 0.01 0.01 0.33 0 0 (Gen: 1)
1720 6152 73400 0.00 0.00 0.02 0.66 0 0 (Gen: 1)
't'
874672 28544 408856 0.00 0.00 0.02 4.14 0 0 (Gen: 0) **
519864 33200 434680 0.00 0.00 0.02 4.14 0 0 (Gen: 0) **
"vxvxvvvxvxvvvxvxvvvxvxvvvxvxvvvxvxvvx"
95504 8424 83680 0.00 0.00 0.02 4.45 0 0 (Gen: 1)
8
9
30992 6984 65824 0.00 0.00 0.02 6.48 0 0 (Gen: 1)
因此需要超过300k(请参阅**
标记的行)来存储18k的文本。 (我已经检查了堆配置文件,它们主要是ARR_WORDS
。)
另一方面,如果我用T.foldl1
替换T.foldl1'
,垃圾收集器就能收回thunk,并且标记的行变为
781336 8432 83680 0.00 0.00 0.02 6.48 0 0 (Gen: 1)
所以它分配的数量相同,但是一旦强制Text
个对象就回收它。我想象我做i / o的方式和我使用的类型的一些组合使它为每个解码的字符串制作一个完整的文件副本(因为37个字符串* 18k = 666k)。
如何让解码过程不分配和保留这么多内存?