这个Scala代码可以使用更少的内存吗?

时间:2011-08-20 18:56:25

标签: scala set memory-management

考虑以下Set基准:

import scala.collection.immutable._

object SetTest extends App {
  def time[a](f: => a): (a,Double) = {
    val start = System.nanoTime()
    val result: a = f
    val end = System.nanoTime()
    (result, 1e-9*(end-start))
  }

  for (n <- List(1000000,10000000)) {
    println("n = %d".format(n))
    val (s2,t2) = time((Set() ++ (1 to n)).sum)
    println("sum %d, time %g".format(s2,t2))
  }
}

编译并运行生成

tile:scalafab% scala SetTest
n = 1000000
sum 1784293664, time 0.982045
n = 10000000
Exception in thread "Poller SunPKCS11-Darwin" java.lang.OutOfMemoryError: Java heap space
...

即,Scala无法在具有8 GB内存的计算机上表示一组1000万个Int。这是预期的行为吗?有没有办法减少内存占用?

3 个答案:

答案 0 :(得分:10)

通用不可变集占用大量内存。默认值仅为256M堆,每个对象只留下26个字节。不可变集的散列特里通常采用每个对象一到两百个字节每个元素额外60个字节。如果在命令行中添加-J-Xmx2G以将堆空间增加到2G,那么你应该没问题。

(例如,这种开销水平是存在位集的一个原因。)

答案 1 :(得分:3)

我对Scala并不熟悉,但这就是我认为正在发生的事情:

首先,整数存储在堆上(必须如此,因为数据结构存储在堆上)。所以我们讨论的是可用堆内存,而不是堆栈内存(只是为了澄清我接下来要说的内容的有效性)。

真正的踢球者是Java的默认堆大小非常小 - 我相信它只有128兆字节(这可能是真正的旧数字,但关键是这个数字存在,而且相当小)。

所以并不是说你的程序使用了太多内存 - 更像是Java本来就没有给你足够的内存。但是有一个解决方案:可以使用-Xms-Xmx命令行选项设置最小和最大堆大小。它们可以像:

一样使用
java -Xms32m -Xmx128m MyClass   (starts MyClass with a minimum heap of 32 megabytes, maximum of 128 megabytes)

java -Xms1g -Xmx3g MyClass (executes MyClass with a minimum heap of 1 gigabytes, maximum of 3 gigabytes)

如果您使用IDE,那么可能还有一些选项可以更改堆大小。

答案 2 :(得分:-1)

这应该总是溢出。在这种情况下不需要保持如此大的值。如果要总和使用迭代器或范围。

val (s2,t2) = time( (1 to n).sum)

上述行在一秒钟内完成,没有溢出。

您始终可以使用其他答案增加内存分配。