相关疑难解决方法(0)

为什么包装Data.Binary.Put monad会造成内存泄漏?(第2部分)

正如在我之前的问题中,我正在尝试将Data.Binary.Put monad包装到另一个monad中,以便稍后我可以问它"它要写多少字节"或"文件中的当前位置是什么"等问题.

之前,我认为理解为什么它在使用一个简单的(IdentityT?)包装器时会泄漏内存会导致我解决我的问题.但即使你们帮我解决了这个简单的包装器的问题,用StateT或WriterT之类的东西包装它仍然会消耗太多的内存(并且通常会崩溃).

例如,这是我试图包装它的一种方式,它为大输入泄漏内存:

type Out = StateT Integer P.PutM ()

writeToFile :: String -> Out -> IO ()
writeToFile path out = BL.writeFile path $ P.runPut $ do runStateT out 0
                                                         return ()

是一个更完整的代码示例,演示了该问题.

我想知道的是:

  1. 程序内部发生什么导致内存泄漏?
  2. 我该怎么办才能修复它?

对于我的第二个问题,我想我应该更详细地解释一下我打算在磁盘上查看数据:它基本上是一个树结构,其中树的每个节点都表示为它的子节点的偏移表(加上一些附加数据).因此,要计算第n个孩子到偏移表中的偏移量,我需要知道子项0到n-1的大小加上当前偏移量(为了简化事情,假设每个节点都有固定数量的子节点).

谢谢你的期待.

更新:感谢nominolo我现在可以创建一个包裹Data.Binary.Put的monad,跟踪当前偏移并几乎不使用任何内存.这是通过放弃使用StateT转换器来支持使用Continuations的不同状态线程机制来完成的.

像这样:

type Offset = Int

newtype MyPut a = MyPut
  { unS :: forall r . (Offset -> a -> P.PutM r) -> Offset -> P.PutM r }

instance Monad MyPut where
  return a = MyPut …

binary monads haskell memory-leaks monad-transformers

6
推荐指数
1
解决办法
537
查看次数

为什么将Data.Binary.Put monad更改为变换器会导致内存泄漏?

我正在尝试将Data.Binary.PutM monad修改为monad转换器.所以我从changin的定义开始

newtype PutM a = Put { unPut :: PairS a }
Run Code Online (Sandbox Code Playgroud)

newtype PutM a = Put { unPut :: Identity (PairS a) }
Run Code Online (Sandbox Code Playgroud)

然后我当然改变了return>> =函数的实现:

从:

return a = Put $ PairS a mempty
{-# INLINE return #-}

m >>= k  = Put $
    let PairS a w  = unPut m
        PairS b w1 = unPut (k a)
    in PairS b (w `mappend` w1)
{-# INLINE (>>=) #-}

m >> k  = Put …
Run Code Online (Sandbox Code Playgroud)

monads haskell memory-leaks monad-transformers

5
推荐指数
1
解决办法
470
查看次数