【发布时间】:2011-06-17 06:23:28
【问题描述】:
我正在尝试将 Data.Binary.Put monad 包装到另一个中,以便稍后我可以问它诸如“它将写入多少字节”或“文件中的当前位置是什么”之类的问题。但即使是非常琐碎的包装,例如:
data Writer1M a = Writer1M { write :: P.PutM a }
or
data Writer2M a = Writer2M { write :: (a, P.Put) }
造成巨大的空间泄漏,程序通常会崩溃(在占用 4GB 的 RAM 后)。到目前为止,这是我尝试过的:
-- This works well and consumes almost no memory.
type Writer = P.Put
writer :: P.Put -> Writer
writer put = put
writeToFile :: String -> Writer -> IO ()
writeToFile path writer = BL.writeFile path (P.runPut writer)
-- This one will cause memory leak.
data Writer1M a = Writer1M { write :: P.PutM a }
instance Monad Writer1M where
return a = Writer1M $ return a
ma >>= f = Writer1M $ (write ma) >>= \a -> write $ f a
type WriterM = Writer1M
type Writer = WriterM ()
writer :: P.Put -> Writer
writer put = Writer1M $ put
writeToFile :: String -> Writer -> IO ()
writeToFile path writer = BL.writeFile path (P.runPut $ write writer)
-- This one will crash as well with exactly the
-- same memory foot print as Writer1M
data Writer2M a = Writer2M { write :: (a, P.Put) }
instance Monad Writer2M where
return a = Writer2M $ (a, return ())
ma >>= f = Writer2M $ (b, p >> p')
where (a,p) = write ma
(b,p') = write $ f a
type WriterM = Writer2M
type Writer = WriterM ()
writer :: P.Put -> Writer
writer put = Writer2M $ ((), put)
writeToFile :: String -> Writer -> IO ()
writeToFile path writer = BL.writeFile path (P.runPut $ snd $ write writer)
我是 Haskell 的新手,这对我来说毫无意义,但包装器 monad 似乎非常微不足道,所以我猜测我缺少一些明显的东西。
感谢收看。
更新: 这是一个演示该问题的示例代码:http://hpaste.org/43400/why_wrapping_the_databinaryp
更新2: 这个问题还有第二部分here。
【问题讨论】:
-
你使用什么编译器标志?
-
在你询问后我尝试了 -O2(我之前没有使用过)但内存占用没有改变。
-
你能发布一个简单的测试程序,这样这里的其他人就不必自己构建了吗?
-
好主意,我很快就会编译一些东西。我可以以某种方式将其发布在 stackoverflow 上还是应该使用 hpaste 代替?
-
我已经尝试过您的示例,并且使用我的 GHC 6.12.3 和 -O2 标志,两个版本都显示几乎相同的时间/空间行为。用
newtype替换“有问题的”包装器中的data可以进一步减少差异。没有 -O2 它绝对是内存贪婪的。你确定你用-O2重新编译了吗?试试-O2 -fforce-recomp
标签: memory haskell memory-leaks binary memory-management