此代码中的空间泄漏在哪里?

时间:2016-04-21 02:55:35

标签: haskell memory-leaks

我试图通过交替行将文件拆分为两个单独的文件。 (即第1,3,5,7行写入文件1和第2,4,6,8行......写入文件2)。

我正在使用的文件大约是700MB,所以当我看到超过6GB的内存使用量时,我知道出了问题。

main :: IO()
main = withFile splitFile ReadMode splitData
  where
    splitData h = do
      dataSet <- lines <$> hGetContents h
      let (s1,s2) = foldl' (\(l,r) x -> (x:r,l)) ([],[]) dataSet
      writeFile testFile $ unlines s1
      writeFile trainingFile $ unlines s2

我最初使用的是懒惰版的foldl,但经过一些研究后,似乎使用严格版本会有所帮助。但唉,它没有明显的区别。我也尝试用-O2进行编译,但这也没有做任何事情。

我正在使用GHC 7.10.2

我没有得到堆栈溢出,那么它使用所有内存是什么?

1 个答案:

答案 0 :(得分:7)

正如@dfeuer在评论中所提到的,使用writeFile将强制写入整个字符串,这也会强制读取整个输入。空间泄漏的原因是,在写入第一个文件时,必须将整个第二个文件保存在内存中,此时很明显,一次只能在内存中保留一行。确实,解决方案是逐行编写:

import Control.Monad 
import System.IO 

main :: IO ()
main = 
  withFile splitFile ReadMode $ \hIn ->  
  withFile testFile WriteMode $ \hOdd ->  
  withFile trainingFile WriteMode $ \hEven ->         
  zipWithM_ hPutStrLn (cycle [hOdd, hEven]) . lines =<< hGetContents hIn

该程序在恒定的空间中运行。