2011-01-28 6 views
12

Data.Binary.Put 모나드를 다른 바이트로 랩핑하려고합니다. 나중에 "쓸 바이트 수"또는 "파일의 현재 위치"와 같은 질문을 나중에 물어볼 수 있습니다. 그러나 심지어 아주 사소한 랩 좋아 :왜 Data.Binary.Put 모나드를 래핑하면 메모리 누수가 발생합니까?

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

거대한 공간의 누출을 만들고 프로그램은 일반적으로 (RAM 4GB의를 복용 후) 충돌합니다. 여기에 지금까지 시도한 것입니다 :

-- 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) 

내가 하스켈에 새로 온 사람이 나에게 어떤 sence을하지 않으며, 그러나 래퍼 모나드 그래서 내가 거기 같은데요 아주 사소한 것 나는 분명히 뭔가 빠져있다.

감사합니다.

UPDATE

: http://hpaste.org/43400/why_wrapping_the_databinaryp

UPDATE2 : 여기 문제를 보여주는 샘플 코드 또한이 질문에 here에 두 번째 부분이있다.

+1

어떤 컴파일러 플래그를 사용하고 있습니까? –

+0

질문을 한 후에 -O2로 시도했지만 (이전에는 아무 것도 사용하지 않았지만) 메모리 발자국이 변경되지 않았습니다. –

+0

다른 사람들이 자신의 테스트 프로그램을 만들 필요가 없도록 간단한 테스트 프로그램을 게시 할 수 있습니까? –

답변

4

, 내가 문제가 이진의 (>> =)를 구현하는의 사용 것 같다 발견 (>>).

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

은 (>>) binary's source 찾고 제 모나드의 결과를 폐기 할 것이 버전이 아직 메모리 누출 반면

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

다음 Writer1M 모나드 구현에 대한 다음의 추가는 문제가 해결 명시 적으로. 하지만 정확히 이것이 누출을 방지하는지는 확실하지 않습니다. 가장 좋은 이론은 GHC가 PairS 객체를 유지하고 "a"참조가 누출되지 않는다는 것입니다.

2

모나드를 더 많이 만들려고 했습니까 ? 예 : 데이터 유형의 생성자를 엄격하게 만들거나 newtype로 바꾸십시오.

정확한 문제는 무엇인지 모르겠지만 이는 일반적인 누출 원인입니다.

PS : 그리고 예를 들어, 불필요한 람다를 제거하려고 : 조금 주위를 파고 후

ma >>= f = Writer1M $ (write ma) >=> write . f 
+0

데이터를 newtype으로 변경하는 것은 #haskell의 좋은 사람들도 제안한 바입니다. 불행히도이를 변경하고 람다를 제거하면 메모리 발자국을 변경하지 않았다고 제안한 것처럼됩니다. 그러나 제안에 감사드립니다. –

+0

프로파일 링을 시도 했습니까? – fuz

+0

예, 결과는 다음과 같습니다. http://i.imgur.com/4Q2E3.png, 래퍼 중 하나를 사용할 때 노란색 영역이 나타납니다. –

관련 문제