【问题标题】:Scala stream keeps intermediary objects in memoryScala 流将中间对象保存在内存中
【发布时间】:2016-10-16 22:07:40
【问题描述】:

我正在尝试在 Scala 中编写一个 Stream,但我不明白为什么它将一些中间对象保留在内存中(并最终耗尽内存)。

这是我的代码的简化版本:

val slols = {
  def genLols (curr:Vector[Int]) :Stream[Int] = 0 #:: genLols(curr map (_ + 1))
  genLols(List.fill(1000 * 1000)(0).toVector)
}
println(slols(1000))

这似乎将中介curr 留在内存中,我不明白为什么。

这是用迭代器编写的相同代码(内存消耗要好得多):

val ilols = new Iterator [Int] {
  var curr = List.fill(1000 * 1000)(0).toVector
  def hasNext = true
  def next () :Int = { curr = curr map (_ + 1) ; 0 }
}
val silols = ilols.toStream
println(silols(1000))

编辑:我有兴趣将0s 保留在内存中,我的目标是不保留currs,因为它们对于采取计算步骤很有用(在我的简化示例中可能并不明显)。并且单独的 0s 不会导致内存不足错误(它们存储起来并不那么重)。

【问题讨论】:

    标签: scala stream stack-overflow memoization


    【解决方案1】:

    当您将流分配给一个变量时,您可以防止它的头部被垃圾收集。

    在第一种情况下,这意味着每次迭代对 cur 向量的所有引用都被记忆。

    在第二种情况下情况更好,因为迭代器一次只存储cur 的单个实例。但是,流的所有 Int 元素仍然被记忆。

    如果您不需要记忆,请尝试将 val slols 替换为 def slols

    顺便说一句,你的两个例子在逻辑上并不等同(可能你已经意识到了)。

    查看this article了解详情。

    【讨论】:

    • 需要明确的是,捕获curr 值的是#:: 的别名参数,而不是流本身。流只记住生成的值——在这种情况下是很多 0。
    • 查看我的编辑,我想保留0s。我知道如果我使用def 将不会有“记忆”,因为每次都会是不同的流(最后一个应该是 GC)(所以我认为它确实记忆了,但没有人因为它无法访问,因此使用def 似乎真的很糟糕)。 J Cracknell,你能告诉我更多关于 by-name 参数的信息吗?我在想它应该被计算和不被引用,但事实并非如此,我不明白为什么。 by-name 有一个明确的关键字 =>
    猜你喜欢
    • 2011-02-22
    • 1970-01-01
    • 2013-02-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-21
    相关资源
    最近更新 更多