Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/iphone/43.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala 构造函数参数是否获得GC';预计起飞时间?_Scala_Constructor_Garbage Collection - Fatal编程技术网

Scala 构造函数参数是否获得GC';预计起飞时间?

Scala 构造函数参数是否获得GC';预计起飞时间?,scala,constructor,garbage-collection,Scala,Constructor,Garbage Collection,我使用的系统需要使用事务初始化许多对象,并且由于超出本问题范围的原因,必须将这些事务传递给构造函数。像这样: trait Mutable class Txn(i: Int) { def newID(implicit m: Mutable): Int = i override def finalize(): Unit = println("Finalised " + i) } class User(t0: Txn) extends Mutable { val id = t0.new

我使用的系统需要使用事务初始化许多对象,并且由于超出本问题范围的原因,必须将这些事务传递给构造函数。像这样:

trait Mutable

class Txn(i: Int) {
  def newID(implicit m: Mutable): Int = i
  override def finalize(): Unit = println("Finalised " + i)
}

class User(t0: Txn) extends Mutable {
  val id = t0.newID(this)
}
现在我担心垃圾收集事务会出现问题:

val u = new User(new Txn(1234))
System.gc()  // hmmm, nothing seems to happen?
所以我的问题是:
t0
constructor参数是否被垃圾收集,或者我是否在这里创建了内存泄漏?在一个等效的Java代码中,我想我会有如下内容:

public class User implements Mutable {
    final int id;
    public User(Txn t0) {
        id = t0.newID(this);
    }
}
我确信
t0
已收集。但在Scala的案例中这是真的吗

如果没有,我如何确保
t0
被垃圾收集?请记住,我必须将事务作为构造函数参数传入,因为
User
类实现了一些必须传递到
Txn
方法中的特性,因此在构造
User
之前不能调用这些方法(如
newID

我以前尝试过在用户对象之外构造所有使用事务的东西,使用大量的
lazy
相互依赖的VAL,但那真的很混乱。例如,这已经有一半无法读取,会产生堆栈溢出:

trait User extends Mutable { def id: Int }

def newUser(implicit tx: Txn): User = {
  lazy val _id: Int = tx.newID(u)
  lazy val u  = new User { val id: Int = _id } // oops, should be lazy val id!
  u
}

val u = newUser(new Txn(1234))

您可以想象,编译器不会在这里发现缺少的惰性val的问题,这真的很糟糕,因此我肯定更喜欢构造函数arg变量。

我曾经遇到的问题似乎是在一个特定的情况下,
System.gc()
不会立即生效

但是我可以观察到最终结果发生在一个普通的REPL中,也发生在一些编译代码中,所以我猜答案是,‘是的,构造函数参数确实会被垃圾收集’

当通过超级类时,它也会起作用,这是另一个好消息:

abstract class Underlying(t0: Txn) extends Mutable {
  val id1 = t0.newID(this)
}

class User(t0: Txn) extends Underlying(t0) {
   val id2 = t0.newID(this)
}

如果构造函数参数未在静态初始值设定项之外使用,则会得到GCed。您可以检查字节码,并验证在这种情况下没有保留对构造函数参数的引用

class WillNotStore(s: Seq[Int]) { val length = s.length }

public WillNotStore(scala.collection.Seq);
  Code:
   0:   aload_0
   1:   invokespecial   #18; //Method java/lang/Object."<init>":()V
   4:   aload_0
   5:   aload_1
   6:   invokeinterface #22,  1; //InterfaceMethod scala/collection/SeqLike.length:()I
   11:  putfield    #11; //Field length:I
   14:  return
类WillNotStore(s:Seq[Int]){val length=s.length}
公共WillNotStore(scala.collection.Seq);
代码:
0:aload_0
1:特别是#18//方法java/lang/Object。“:()V
4:aload_0
5:aload_1
6:调用接口#22,1//接口方法scala/collection/SeqLike.长度:()I
11:putfield#11//字段长度:I
14:返回

请注意,参数已加载(第5行)并在其上调用了一个方法(第6行),但在构造函数退出(第14行)之前只存储了答案(第11行)。

如果绝对必要,我建议您使用
javap
查看类编译成了什么。避免将构造函数参数转换为类参数的一些规则:

  • 不要在
    def
    lazy val
    上使用它
  • 不要在模式匹配的赋值中使用它(比如
    val(a,b)=f(x)
  • 当然,不要将其声明为
    val
    var

哈!我刚刚告诉他要使用javap,现在你用它来回答他的问题。:-)@DanielC.Sobral-
scala-cp/path/to/tools.jar
+
:javap-c WillNotStore
只需几秒钟……@Sciss-Daniel的答案更完整;甚至在初始值设定项中的模式匹配也是一个奇怪的特例,我已经忘记了
DelayedInit
是另一种方法(尽管它在那里更明显是必要的,因为它在概念上类似于
lazy val
),检查可能是最好的建议!最简单的检查方法通常是在javap中使用
-private
标志,而不用担心字节码。这将首先列出私有字段(使用Java语法),其中将包含类似于构造函数参数的
x$1