以下程序在运行可执行文件(通过ghc -O0 Explode.hs
编译)时不会爆炸,但在ghci中运行时会爆炸(通过{{ 1}}或ghci Explode.hs
):
ghci -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中爆炸?我在Memory blowing up for strict sum/strict foldl in ghci中采用的方法似乎不适用于此。感谢。
答案 0 :(得分:2)
在检查writeFile
的代码后,它似乎取决于hPut
的{{1}}函数:
Data.ByteString.Lazy
-- | 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
查看代码,似乎在写入第一个字节之前,将强制执行lazy bytestring的“spine”(但不是每个chunk中的实际数据),因为-- | 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)
的行为对于(>>)
monad。
在您的示例中,组成懒惰字节串的严格块非常小。这意味着当IO
“强制执行100000000字符长延迟字节字符串的脊椎”时,将生成很多这些字符串。
如果这种分析是正确的,那么通过使它们变大来减少严格块的数量将减少内存使用量。 foldrChunks
的这种变体可以创建更大的块,但这并不会让我在ghci中爆炸:
createStr
(我不确定为什么编译的例子不会爆炸。)