以下定义会导致内存泄漏:
泄漏可以通过以下测试观察到:
然而,一个微小的变化(即将
def enumIterator1[E, F[_]: Monad](x: => Iterator[E]) : EnumeratorT[E, F] =
new EnumeratorT[E, F] {
def apply[A] = (s: StepT[E, F, A]) => {
def go(xs: Iterator[E]): IterateeT[E, F, A] =
if(xs.isEmpty) s.pointI
else {
val next = xs.next
s mapCont { k =>
k(Iteratee.elInput(next)) >>== enumIterator1[E, F](xs).apply[A]
}
}
go(x)
}
}
泄漏可以通过以下测试观察到:
(Iteratee.fold[Array[Byte], IO, Long](0L)(_+_.length)
&= enumIterator1(
Iterator.continually(
Array.fill(1 << 16)(0.toByte)).take(1 << 16))
).run.unsafePerformIO
然而,一个微小的变化(即将
xs.next
调用移动)就可以防止内存泄漏:def enumIterator1[E, F[_]: Monad](x: => Iterator[E]) : EnumeratorT[E, F] =
new EnumeratorT[E, F] {
def apply[A] = (s: StepT[E, F, A]) => {
def go(xs: Iterator[E]): IterateeT[E, F, A] =
if(xs.isEmpty) s.pointI
else {
// val next = xs.next (moved down)
s mapCont { k =>
val next = xs.next
k(Iteratee.elInput(next)) >>== enumIterator1[E, F](xs).apply[A]
}
}
go(x)
}
}
为什么?
我有一个模糊的概念,认为这种行为与闭包的引用模式有关,但我无法提供具体原因。我正在追踪另一个内存泄漏,我怀疑(希望?)了解这个泄漏可能有助于确定那个问题的原因。
mapCont
的匿名函数参数会被enumIterator1
的按名称参数所引用?(我猜你是指enumIterator1
而不是enumIterator
) - Aaron Novstrupouter$
找到了xs
。 - James_picjavap
中查看它们来弄清楚相应的类是做什么的。但无论如何,简化都应该使事情更清晰。 - James_picEnumeratorT.scala
的提交历史可能会很有帮助。具体来说,这些 提交记录。;-) - Aaron Novstrup