2017-04-21 6 views
1

我正在瀏覽Functional Systems in Haskell的幻燈片。在講座中,存在使用unsafeInterleaveIO列出目錄中的遞歸的所有文件中定義recDir2功能:cs240:recDir在兩種類似情況下使用的額外150 MB

import qualified Data.ByteString.Lazy  as L 

recDir2 :: FilePath -> IO [FilePath] 
recDir2 dir = do 
    ds <- openDirStream dir 
    let protect m = m `onException` closeDirStream ds 

     nextName = unsafeInterleaveIO $ 
       protect (readDirStream ds) >>= checkName 

     checkName "" = closeDirStream ds >> return [] 
     checkName "." = nextName 
     checkName ".." = nextName 
     checkName name = getSymbolicLinkStatus path >>= checkStat path 
      where path = dir </> name 

     checkStat path stat 
      | isRegularFile stat = liftM (path :) nextName 
      | isDirectory stat = 
       liftM2 (++) (protect $ recDir2 path) nextName 
      | otherwise = nextName 

    nextName 

readFiles :: [FilePath] -> IO L.ByteString 
readFiles [] = return L.empty 
readFiles (f:fs) = liftM2 L.append (L.readFile f) 
        (unsafeInterleaveIO $ readFiles fs) 

此功能在兩個看似相同的情況後使用:

*Main> recDir2 "/usr/include" >>= readFiles >>= print . L.length 

*Main> x <- recDir2 "/usr/include" >>= readFiles 
*Main> L.length x 

但是在幻燈片中指出,第二種情況使用額外的150 MB,但我沒有看到原因。什麼導致這種據稱額外的內存使用?

+1

我的猜測是:後者無法垃圾收集'x',因爲它被消耗掉了。什麼是'L'和'readFiles'?在不知道代碼的情況下可靠地檢查這種猜測是很難的。 –

+0

我添加了'L'和'readFiles'的定義。在第二種情況下,有什麼收集?由於'readFiles'中的列表是根據需要構建的...... –

回答

5

比較這對:

> let xs = [1..999999999] 
> length xs 

> length [1..999999999] 

在第二種情況下,垃圾收集器清理名單,因爲它是被消耗,讓你用很少的內存。但是在第一種情況下,您仍然會參考xs,並且您可能隨時鍵入xs !! 555。所以垃圾收集器必須爲你保留整個xs在內存中。

同樣在你的例子中,一個版本有一個引用x,可能會在以後重用,所以x的內容必須保留。

+1

您可能想指出這是GHCI中的。在GHC計劃中,前者將針對後者變體進行優化。 –