Scala中对象引用的成本是多少?

phi*_*dad 3 oop jvm scala

假设我们构建一个对象来表示一些网络(社交,无线,等等).所以我们有一些'node'对象来表示网络的KIND,不同的节点可能有不同的行为,等等.网络具有MutableList节点.

但每个节点都有邻居,这些邻居也是节点.所以在某个地方,每个节点必须有一个该节点的所有邻居的列表 - 或者这样的列表必须在需要时动态生成.如果邻居列表存储在节点对象中,将它(a)存储为节点列表,或者(b)作为可用于引用网络外节点的数字列表是否更便宜?

一些代码为清晰起见:

//approach (a)

class network {
  val nodes = new MutableList[Node]
  // other stuff //
}

class Node {
  val neighbors = new MutableList[Node]
  // other stuff //
}

//approach (b)
class Network {
  val nodes = new MutableList[Node]
  val indexed_list = //(some function to get an indexed list off nodes)
//other stuff//
}

class Node {
  val neighbors = MutableList[Int]
//other stuff//
}
Run Code Online (Sandbox Code Playgroud)

方法(a)似乎最简单.我的第一个问题是Scala 2.8中这是否代价高昂,第二个问题是它是否违反DRY的原则?

Jam*_*Iry 9

简短回答:过早优化是其中的根源等.使用干净的参考方法.当您遇到性能问题时,无法替代分析和基准测试.

答案很长:Scala使用与Java完全相同的引用机制,因此这比Jala问题更像是一个JVM问题.正式地,JVM规范没有说明如何实现引用.在实践中,它们往往是字大小或更小的指针,指向对象或索引到指向对象的表(后者帮助垃圾收集器).

无论哪种方式,refs数组的大小与32位vm上的int数组大小相同,或者在64bit vm上大约两倍(除非使用压缩oops).这种倍增可能对你很重要,也可能不重要.

如果使用基于ref的方法,则从节点到邻居的每次遍历都是参考间接.使用基于int的方法,从节点到邻居的每次遍历都是查找表,然后是参考间接.因此int方法在计算上更昂贵.这就是假设你将整数放入一个不包含整数的集合中.如果你打算使用int,那么它只是纯粹的疯狂,因为现在你有了与原始AND一样多的引用并且你有一个表查找.

无论如何,如果你使用基于引用的方法,那么额外的引用可以为垃圾收集器做一些额外的工作.如果对节点的唯一引用位于一个数组中,那么gc将快速扫描那个节点.如果它们分散在图表中,那么gc将不得不更加努力地追踪它们.这可能会也可能不会影响您的需求.

从清洁的角度来看,基于ref的方法要好得多.所以一起去,然后剖析一下,看看你在哪里花时间.那个或基准都接近.