2011-05-09 104 views
2

在几个地方我都看到了类似的声明:斯卡拉“原始”优化

“Scala编译器使用Java数组,基本类型,和本地运算在可能的编译代码” (编程在斯卡拉书)。 但在实践中我没有看到这一点,例如在下面的代码,阶类型是使用比Java类型更多的存储器(我通过使用totalMemory和freeMemory的方法计算):

long[] la = new Array[java.lang.Long](1024 * 1024); 
for(i <- 0 until la.length) 
    la(i) = new java.lang.Long(0); 

val La = new Array[Long](1024 * 1024); 
for(i <- 0 until La.length) 
    La(i) = 0l; 

mem_used( Java的长):>> 28.811M

mem_used(阶长):>> 36.811M

我认识的任何类型都有额外的开销阶,但如果是优化发生?

+1

您的测量内存使用情况的方法必须错误。你得到的结果是无意义的。 – 2011-05-09 15:29:33

+0

除了上面提到的其他问题,Scala程序从Scala库中提取额外的类是很有可能的。 – ziggystar 2011-05-09 16:32:19

回答

9

为什么要用这种复杂的方式来试图找出什么被编译成什么?只需在一个班上运行javap,你就会看到正是它是什么。

C:\>type La.scala 
class La { 
    val La = new Array[Long](1024 * 1024); 
} 

C:\>javap La 
Compiled from "La.scala" 
public class La extends java.lang.Object implements scala.ScalaObject{ 
    public long[] La(); 
    public La(); 
} 
2

正如Runtime.freeMemory的文档所述,返回值取决于最后一次gc完成的时间。所以这个错误很可能以你的测量方式。

+0

对不起,我应该提到我在每个之间运行gc。我知道,不能保证任何清理工作已经完成,但在这个微不足道的案例中你会希望如此。 – David 2011-05-09 16:08:31

+0

由于您只分配大约8MB,垃圾收集器可能不认为有必要清理。您应该张贴测量代码。 – 2011-05-09 16:42:34

1

在Java中测量内存使用真的很难。你所做的任何涉及内存子系统的操作都会导致结果波动很大 - 即使你什么也不做,你不能确定JVM不是为了自己运行而创建对象。尤其是,您应该使用while循环而不是for循环以填充数组(以避免在for中创建任何对象)。然后再次,创建该数组的内存分配可能会触发垃圾回收。您最好的选择是使用-verbose:gc运行jvm以确保在您的测量之间不会发生垃圾收集,例如,

println("Starting") 
// Measure free memory 
// Create some stuff 
// Measure free memory 
println("Ending") 

如果您看到GC处于启动和结束之间,请忽略该运行。