【问题标题】:Scala "primitive" optimisationScala“原始”优化
【发布时间】:2011-05-09 14:58:52
【问题描述】:

我在几个地方看到过类似的声明:

“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):>> 28.811M

mem_used (scala long):>> 36.811M

我意识到 scala Any 类型有额外的开销,但是优化发生在哪里?

【问题讨论】:

  • 您测量内存使用的方法一定是错误的。你得到的结果是荒谬的。
  • 除了提到的其他问题之外,Scala 程序很有可能正在从 Scala 库中引入其他类。

标签: optimization scala types primitive


【解决方案1】:

为什么要费心用如此复杂的方式来找出编译成什么的呢?只需在一个类上运行 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 完成的时间。所以这个错误很可能是你的测量方式。

    【讨论】:

    • 对不起,我应该提到我在每个之间运行 gc。我知道,不能保证任何清理工作都已完成,但在这种微不足道的情况下,您希望如此。
    • 由于您只分配了大约 8MB,垃圾收集器可能认为还没有必要清理。您应该发布测量代码。
    【解决方案3】:

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

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

    如果您看到 GC 介于 Starting 和 Ending 之间,请忽略该运行。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-04-08
      • 2023-04-05
      • 2020-01-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多