我目前正在尝试将XML文件的内容读入Map Int (Map Int String)
并且它运行良好(使用HaXml)。但是,我对我的程序的内存消耗不满意,问题似乎是垃圾收集。
这是我用来读取XML文件的代码:
type TextFile = Map Int (Map Int String)
buildTextFile :: String -> IO TextFile
buildTextFile filename = do content <- readFile filename
let doc = xmlParse filename content
con = docContent (posInNewCxt filename Nothing) doc
return $ buildTF con
我的猜测是content
即使在返回后仍保留在内存中,尽管它不需要(当然它也可以是doc
或{ {1}})。我得出这个结论是因为内存消耗随着非常大的XML文件而迅速上升,尽管结果con
只是单例映射的单例映射(使用特殊的测试文件,当然通常它是不同的)。所以最后,我有一个TextFile
Map
,其中只有一个字符串,但内存消耗最多为19 MB。
在Map Int String
中使用严格的申请($!
)或使用Data.Text
代替String
不会改变任何内容。
所以我的问题是:是否有某种方法可以告诉编译器不再需要字符串TextFile
(或content
或doc
)并且可以进行垃圾回收?
更一般地说:如果没有猜测,我怎样才能找出问题的真正来源?
编辑:正如FUZxxl建议我尝试使用deepseq并更改con
的第二行,如下所示:
buildTextFile
不幸的是,这并没有真正改变任何东西(或者我使用它错了?)......
答案 0 :(得分:2)
不要猜猜什么是消耗内存,一目了然
第一步是确定消耗最多内存的类型。你可以在SO上看到很多堆分析的例子,或者阅读GHC manual。
强制计算
如果问题是延迟评估(你正在构建一个可以计算XML文档类型并将字符串留在堆中的堆上thunk),那么使用rnf和seq:
buildTextFile :: String -> IO TextFile
buildTextFile filename = do content <- readFile filename
let doc = xmlParse filename content
con = docContent (posInNewCxt filename Nothing) doc
res = buildTF con
return $ rnf res `seq` res
或者只是使用爆炸模式(!res = buildTF con
),无论哪种方式都应该强制使用thunk并允许GC收集String
。