为什么包裹Data.Binary.Put单子造成内存泄漏? [英] Why wrapping the Data.Binary.Put monad creates a memory leak?

查看:133
本文介绍了为什么包裹Data.Binary.Put单子造成内存泄漏?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想换行Data.Binary.Put单子到另一个,这样以后我可以问它问题,如它会如何写入的字节数或什么是在文件的当前位置。但即使是很琐碎包装,如:

I'm trying to wrap the Data.Binary.Put monad into another so that later I can ask it questions like "how many bytes it's going to write" or "what is the current position in file". But even very trivial wraps like:

data Writer1M a = Writer1M { write :: P.PutM a }
or
data Writer2M a = Writer2M { write :: (a, P.Put) }

创造了巨大的空间泄漏,程序通常会崩溃(占4GB的RAM后)。这是我到目前为止已经试过:

create a huge space leak and the program usually crashes (after taking up 4GB of RAM). Here is what I've tried so far:

-- 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,这使得没有SENCE给我,但包装单子看起来很琐碎所以我猜有一些明显的我失踪。

I'm new to Haskell and this makes no sence to me, but the wrapper monads seem very trivial so I'm guessing there is something obvious I'm missing.

感谢您寻找。

更新:
下面是一个示例code演示该问题: http://hpaste.org/43400/why_wrapping_the_databinaryp

UPDATE2:
还有一个第二部分这个问题<一href=\"http://stackoverflow.com/questions/5019655/why-wrapping-the-data-binary-put-monad-creates-a-memory-leak-part-2\">here.

推荐答案

闲逛了一会儿后,我发现这个问题似乎是二进制的(>> =)的使用来实现(>>)。下面除了Writer1M单子实施解决了这个问题:

After poking around for a bit, I found that the problem seems to be the usage of binary's (>>=) to implement (>>). The following addition to the Writer1M monad implementation solves the problem:

  m >> k = Writer1M $ write m >> write k

而这个版本仍然出现内存泄漏:

Whereas this version still leaks memory:

  m >> k = Writer1M $ write m >>= const (write k)

看着<一个href=\"http://hackage.haskell.org/packages/archive/binary/0.5.0.2/doc/html/src/Data-Binary-Put.html#line-96\"相对=nofollow>二进制的源时,(>>)似乎明确地丢弃所述第一单子的结果。不知道这$ P $究竟pvents泄漏,虽然。我最好的理论是,GHC否则就会保存对对象,而一引用泄漏,因为它永远不会看。

Looking at binary's source, (>>) seems to discard the result of the first monad explicitly. Not sure how exactly this prevents the leak, though. My best theory is that GHC otherwise holds onto the PairS object, and the "a" reference leaks because it never gets looked at.

这篇关于为什么包裹Data.Binary.Put单子造成内存泄漏?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆