在Haskell中解析二进制文件时如何减少垃圾收集?

sda*_*das 7 optimization haskell

我正在编写一个程序来使用Haskell解析.TGA文件 - 但是,性能绝对可怕.2048 x 2048像素图像需要几秒钟才能解析.

我运行了我的代码+RTS -p -RTS并收到了报告中的以下有趣内容:

total time = 1.08 secs
total alloc = 3,037,568,120 bytes

COST CENTRE           MODULE    %time    %alloc
readPixelMap            Main     33.0      11.0
readPixelMap.getByte    Main     32.7      75.1
readPixelMap.getColor   Main     27.0      13.3
Run Code Online (Sandbox Code Playgroud)

看来我的程序在函数中分配了大量的内存readPixelMap.该函数如下所示:

readPixelMap width height = do
    pixels <- replicateM height (replicateM width getColor)
    return $ PixMap pixels
    where getByte = liftM toInteger getWord8
          getColor = do (red:green:blue:alpha:xs) <- replicateM 4 getByte
                        return (red, green, blue, alpha)
Run Code Online (Sandbox Code Playgroud)

和a PixMap定义为

data PixMap = PixMap [[RGBAColor]] deriving (Show)
type RGBAColor = (Integer, Integer, Integer, Integer)
Run Code Online (Sandbox Code Playgroud)

readPixelMap使用Getmonad来调用Data.Binary:

main = do
    binary <- BS.readFile "test.tga"
    let (pixelMap, binary', nil) = runGetState (readPixelMap 2048 2048) binary 0
Run Code Online (Sandbox Code Playgroud)

我一直在努力工作的印象是2048 x 2048 .TGA图像应加载到几百兆(最多)的内存中.有没有明显的方法来改善我的垃圾收集时间/分配金额?

Car*_*arl 12

您的RGBColor类型使用5个机器字,其中4个是每个机器字的指针Integer.每个Integer包含一个用于GC /标记的机器字,以及用于小型表示的一个附加字,或者包含指向GMP数据的字节数组的指针和肢体计数的大型表示.

此外,您正在使用列表列表来存储值.每个非空列表节点是用于GC /标记的单词,指向该值的单词指针,以及指向尾部的单词指针.

要使用更少的内存,请使用适当的数据类型.尽可能使用未打包的值.使用Word8而不是Integer8位值.使用数组而不是列表.你知道,像你一样关心记忆的基本知识.

请查看http://johantibell.com/files/slides.pdf了解一些基础知识.