4

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

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

这是声音吗?一旦访问lazy val,合成初始化字段是否会被取消引用?如果我想在初始化函数中使用它怎么办,如下所示:

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

在使用闭包进行编程时,一般有什么规则需要牢记吗?

4

1 回答 1

4

您所描述的主要问题 - 索引不能被垃圾收集 - 通过将索引放入一个可变的盒子中来解决,一旦创建了对象,您就清空(null out)。

然而,如果你不知道你的对象是什么时候创建的,并且需要程序告诉你(例如,通过知道所有惰性 val 都已被填充),那么你就不走运了。除非在内存中四处sun.misc.Unsafe寻找,否则您不应该知道这些细节。(这就是惰性 vals 的意义所在。)

您可以制定一个引用计数方案,当您可以清除该框时,它可以帮助您检测自己:当您进入构造函数时,在框上增加一个计数器,保留一个私有字段计数您有多少惰性 val,以及每次初始化惰性 val 时都会减少该计数(原子地!),如果您达到零,则减少盒子上的计数器,如果盒子计数器达到零,则将盒子归零。

于 2015-05-26T17:03:17.773 回答