如何避免Haskell空间泄漏? [关闭]
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何避免Haskell空间泄漏? [关闭]相关的知识,希望对你有一定的参考价值。
Context
我不久前开始通过解决今年的代码问世任务来开始学习Haskell。
在解决Part 2 of Day 17时,我遇到了令人讨厌的内存泄漏(空间泄漏) - 我想。
(这是完整的README,包括第2部分,只有在解决第1部分后才能访问它。)
我的解决方案工作正常,但只有一个脏的小黑客,这迫使Haskell不时地评估一个中间计算。
我在每5000次迭代后使用traceShow
将中间状态打印到控制台(请参阅此处the actual code)。这样程序在合理的时间内完成,并且不会使用太多内存。
问题:如果我删除它(根本不打印中间状态,只打印最后一个状态),程序将占用所有可用内存。 :(
我开始使用iterate
,然后我读到使用它会导致像我注意到的东西。我已经取代了它。没有。试过不同的褶皱(foldl
,foldl'
等)。没有。我不确定在这一点上可能导致这种情况的原因虽然我的猜测是在某些时候还有一些不那么明显的懒惰评估正在进行中。
我的问题:我怎么能避免这个?是什么导致我的情况?
感谢您的时间和见解。哦,我很确定这个问题有更短,更甜的解决方案,但目前我只对导致内存泄漏的原因感兴趣。
Testing
我已经隔离了我注意到这个错误的代码部分。
type Count = Int
type StepSize = Int
type Value = Int
type Position = Int
type Size = Int
data Buffer = Buffer Size Position (Maybe Value)
deriving Show
data Spinlock = Spinlock StepSize !Position !Value Buffer
deriving Show
updateBuffer :: Position -> Value -> Buffer -> Buffer
updateBuffer position value (Buffer size trackedPosition trackedValue)
| position == trackedPosition = Buffer nextSize trackedPosition (Just value)
| otherwise = Buffer nextSize trackedPosition trackedValue
where nextSize = size + 1
stepSpinlock :: Count -> Spinlock -> Spinlock
stepSpinlock count spinlock@(Spinlock stepSize position value buffer)
| count == 0 = spinlock
| otherwise = stepSpinlock nextCount newSpinlock
where (Buffer size _ _) = buffer
nextCount = count - 1
nextPosition = ((position + stepSize) `mod` size) + 1
nextValue = value + 1
newBuffer = updateBuffer nextPosition nextValue buffer
newSpinlock = Spinlock stepSize nextPosition nextValue newBuffer
main = do
let stepSize = 371
buffer = Buffer 1 0 Nothing
spinlock = Spinlock stepSize 0 0 buffer
(Spinlock _ _ _ (Buffer _ _ (Just value))) = stepSpinlock (50000000 - 1) spinlock
print $ value
我用stack
(lts-10.1
),GHC 8.2.2来运行它。
运行这会占用我所有的内存并且在一段时间后无法分配内存错误而失败。
如果我替换它
| otherwise = stepSpinlock nextCount newSpinlock
有了这个
| otherwise = stepSpinlock nextCount $ if count `mod` 5000 == 0
then traceShow newSpinlock newSpinlock
else newSpinlock
它运行在合理的时间。然后用stack ghc Part2.hs
重新编译然后再次运行./Part2 < input.txt
。
以下作品:
{-# language BangPatterns #-}
...
stepSpinlock :: Count -> Spinlock -> Spinlock
stepSpinlock count spinlock@(Spinlock !stepSize !position !value !buffer)
...
在每次迭代中,您更新value
和buffer
而不对它们做任何事情,因此thunk积累。或者,我建议只使用{-# language Strict #-}
。我还注意到在使用CircularBuffer
的程序运行期间根本没有使用input.txt
。
以上是关于如何避免Haskell空间泄漏? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章
在 Haskell 中 Floyd-Warshall 的表现——修复空间泄漏