Scala:清理构造函数参数

时间:2014-10-25 17:20:48

标签: scala parameters constructor garbage-collection

我只是在学习Scala,并担心清理构造函数参数。

在Java中,我有一个这样的课程:

public class Example {
    private A a;
    private B b;

    private SelectorA aSelector;
    private SelectorB bSelector;

    public Example(SelectorA aSelector, SelectorB bSelector) {
        this.aSelector = Objects.requireNonNull(aSelector);
        this.bSelector = Objects.requireNonNull(bSelector);
    }

    public void start() {
        if (a == null) {
            a = aSelector.select();
            aSelector = null; // Removing reference.
        }

        if (b == null) {
            b = bSelector.select();
            bSelector = null; // Removing reference.
        }

        // Go on.
    }
}

当然,它更复杂,有参数和东西。这个课程假设是一个长寿的课程,我只是想确保它没有任何它不需要的参考。

我即将把这个类移植到Scala并创建了这样的类:

class Example(_aSelector: Selector[A], _bSelector: Selector[B]) {
    private lazy val _a = _aSelector() // Will _aSelector reference be cleared?
    private lazy val _b = _bSelector() // Will _bSelector reference be cleared?

    def start() = {
        // Use _a.
        // Use _b.
        // Go on.
    }
}

同样,它会更复杂,但这个想法很清楚。所以,问题是:

Scala是否能够检测不再需要哪些构造函数参数(上例中的_aSelector_bSelector)?或者我是否必须明确清除参考文献?

_a
_aSelector = null
_b
_bSelector = null

P.S。我理解GC是检测范围外引用的那个,但Scala编译器是定义变量范围的一个,因此它是一个定义行为。

2 个答案:

答案 0 :(得分:6)

使用lazy val,您明确请求_a仅在第一次访问时初始化。这需要在构造函数结束后保留​​对_aSelector的引用,至少在第一次访问_a之前。

然而 - 这让我感到惊讶 - 看来scalac非常聪明,可以在_aSelector成功初始化后生成_a的代码。

您可以使用scalac -Xprint:mixin验证这一点:

<强> Test.scala:

class Test(factory: () => Int) {
  lazy val x = factory()
}

然后:

$ scalac -Xprint:mixin Test.scala
class Test extends Object {
  @volatile private[this] var bitmap$0: Boolean = false;
  private def x$lzycompute(): Int = {
    {
      Test.this.synchronized({
        if (Test.this.bitmap$0.unary_!())
          {
            Test.this.x = Test.this.factory.apply$mcI$sp();
            Test.this.bitmap$0 = true;
            ()
          };
        scala.runtime.BoxedUnit.UNIT
      });
      Test.this.factory = null // <-- LOOK HERE
    };
    Test.this.x
  };
  <paramaccessor> private[this] val factory: Function0 = _;
  lazy private[this] var x: Int = _;
  <stable> <accessor> lazy def x(): Int = if (Test.this.bitmap$0.unary_!())
    Test.this.x$lzycompute()
  else
    Test.this.x;
  def <init>(factory: Function0): Test = {
    Test.this.factory = factory;
    Test.super.<init>();
    ()
  }
};

因此,第一次访问_a并成功初始化后,,将释放对_aSelector的引用,GC将能够收回它。

答案 1 :(得分:0)

你不能在这里使用WeakReferences来允许GC在弱引用时清除引用,然后只需更改你的防护以确定它们是否仍然可用?如果他们不是注入选择器,那么可以注入一个知道如何创建新引用的工厂。一种老化的缓存方法......