2014-07-27 19 views
2

到文件以下程序不爆炸時可執行(經由ghc -O0 Explode.hs編譯)運行時,但確實爆炸在ghci中運行時(通過任一ghci Explode.hsghci -fobject-code Explode.hs):存儲器爆炸時寫入懶惰字節串中ghci中

--Explode.hs 
--Does not explode with : ghc -O0 Explode.hs 
--Explodes with   : ghci Explode.hs 
--Explodes with   : ghci -fobject-code Explode.hs 
module Main (main) where 
import Data.Int 
import qualified Data.ByteString.Lazy as BL 
import qualified Data.ByteString.Lazy.Char8 as BLC 

createStr :: Int64 -> String -> BL.ByteString 
createStr num str = BL.take num $ BL.cycle $ BLC.pack str 

main = do 
    BLC.writeFile "results.txt" $ createStr 100000000 "abc\n" 

它爲什麼會爆炸在ghci中,不與ghc -O0 Explode.hs,我怎麼能阻止它在ghci中爆炸?我在Memory blowing up for strict sum/strict foldl in ghci中採用的方法似乎在這裏工作。謝謝。

+1

您可以留下' - O0':['-O0'如果不與另一個'-O *'標誌一起使用,實際上會被忽略](https://www.haskell.org/ghc/docs/latest/html/users_guide/options-optimise.html) 。 – Zeta

回答

2

檢查的writeFile代碼後,它似乎取決於Data.ByteString.LazyhPut功能:

-- | Outputs a 'ByteString' to the specified 'Handle'. 
-- 
hPut :: Handle -> ByteString -> IO() 
hPut h cs = foldrChunks (\c rest -> S.hPut h c >> rest) (return()) cs 

hPut構建IO行動,將通過在應用某種形式的右折打印懶字節字符串塊。對於foldrChunks功能的來源是:

-- | Consume the chunks of a lazy ByteString with a natural right fold. 
foldrChunks :: (S.ByteString -> a -> a) -> a -> ByteString -> a 
foldrChunks f z = go 
    where go Empty  = z 
     go (Chunk c cs) = f c (go cs)  

看代碼,它好像在偷懶字節串的「脊樑」(而不是在每個塊的實際數據)將被寫入第一個字節之前被迫,因爲(>>)表現爲IO monad。

在你的例子中,構成懶惰字節串的嚴格塊非常小。這意味着當foldrChunks「強制突破100000000個字符長的懶惰字節串」時,將會生成很多這樣的字符串。

如果這種分析是正確的,那麼通過增大它們來減少嚴格塊的數量會減少內存使用量。的createStr這種變異,創造更大的塊不會在ghci中炸燬了我:

createStr :: Int64 -> String -> BL.ByteString 
createStr num str = BL.take num $ BL.cycle $ BLC.pack $ concat $ replicate 1000 $ str 

(我不知道爲什麼編譯的例子並不炸燬。)

+0

我不明白爲什麼應該強制懶惰字節串的脊椎。 '(>>)在執行第一個參數之前在第二個參數中不是嚴格的。如果不是懶惰的話,'foldrChunk'將會毫無用處。 –

+0

@danidiaz:感謝您的詳細解答。我唯一沒有得到的是,如果你的論證成立,那麼它應該也跟着'BLC.writeFile「results.txt」$ BL.cycle $ BLC.pack「abc \ n」'不應該寫出任何內容「results.txt」,因爲無限的脊椎將不得不被迫。然而,人們發現如果運行這樣的代碼並放棄它,那麼「results.txt」實際上就會填充結果。 – artella

+0

@artella閱讀Ørjan的評論和你自己的評論後,我擔心我的解釋是不正確的。你應該不接受它。 – danidiaz