首页 文章

Scala:懒惰的val,按名称调用,闭包和内存泄漏

提问于
浏览
4

我有一个scala过程,在过程中使用更大的索引创建一个大型数据结构 . 因为我想在一次传递中完成并且不会在复杂的优先级解析中被忽略,所以我在使用表达式初始化的结果中使用延迟val,这些表达式在创建时可能无法评估为正确的值(或任何值)组件,但一旦整个构建过程完成,它将这样做 . 这意味着最终结果的每个组件都有一个对我的整个索引的闭包的合成引用,并且可能,只要它们中的任何一个仍在内存中,我的索引就不能被垃圾收集 . 显然,我不想要它 - 理想情况下我希望能够在结构上进行第二次传递以在需要时初始化值(并确保此时捕获任何错误),并让索引为垃圾收集 . 目前我通过几个函数按名称传递初始化表达式,并在lazy val声明中使用它,相当于:

class Component(init : =>Component) {
   lazy val property = init
}
...
new Component(index.get(parameters))

这听起来不错?一旦访问了懒惰的val,是否会解除引用合成的init字段?如果我想在初始化函数中使用它,如下所示:

class Component(init : =>Component) {
   private def evaluate = init
   lazy val property = evaluate
}

在使用闭包进行编程时,是否有任何规则要记住?

1 回答

  • 4

    您正在描述的主要问题 - 索引不能被垃圾收集 - 通过将索引放入一个可变框中来解决,该框在创建对象后清空(null) .

    但是,如果你不知道你的对象何时被创建,并且需要程序告诉你(例如,知道已经填充了所有的懒人),那么你运气不好 . 除非使用 sun.misc.Unsafe 在内存中进行探索,否则你就是懒惰的点 . )

    你可以编写一个引用计数方案,它可以帮助你在清除方框时检测自己:在你输入构造函数时在框上增加一个计数器,保持一个私有字段计数你有多少懒惰值,以及每次初始化一个惰性值时递减计数(原子!),如果你达到零,则递减计数器上的计数器,如果盒计数器达到零,则为空 .

相关问题