在一些地方,我看到过类似的声明:
“Scala编译器在编译代码中尽可能使用Java数组,原始类型和本机算法” (在Scala书中编程)。 但实际上我没有看到这一点,例如在下面的代码中,scala类型使用的内存多于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 long):&gt;&gt; 28.811M
mem_used(scala long):&gt;&gt; 36.811M
我意识到scala任何类型都有额外的开销,但优化发生在哪里?
答案 0 :(得分: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();
}
答案 1 :(得分:2)
正如Runtime.freeMemory的文档所说,返回的值取决于最后一次gc的完成时间。所以错误很可能是你测量的方式。
答案 2 :(得分:1)
在Java中测量内存使用情况真的很难。你做的任何触及内存子系统的事情都会导致结果波动很大 - 即使你什么都不做,你也不能确定JVM是不是在创建对象以便自己运行。特别是,您应该使用while
循环而不是for
循环来填充数组(以避免在for
中创建任何对象)。然后,创建数组的内存分配可能会触发垃圾回收。最好的办法是使用-verbose:gc
运行jvm,以确保测量之间不会发生垃圾收集,例如
println("Starting")
// Measure free memory
// Create some stuff
// Measure free memory
println("Ending")
如果你看到GC介于开始和结束之间,请忽略该运行。