2011-11-25 30 views
5

我有一个非常大的数字列表,它经历了大量的数学操作。我只关心最后的结果。要模拟这种行为,请参阅下面的示例代码:斯卡拉的范围和内存问题

object X { 
def main(args:Array[String]) = { 
    val N = 10000000 
    val x = List(1 to N).flatten 
    println(x.slice(0,10)) 
    Thread.sleep(5000) 
    val y = x.map(_*5) 
    println(y.slice(0,10)) 
    Thread.sleep(5000) 
    val z = y.map(_+4) 
    println(z.slice(0,10)) 
    Thread.sleep(5000) 
} 
    } 

所以x是一个非常大的列表。我只关心结果z。为了获得z,我首先必须用数学方法处理x来得到y。然后我操纵y得到z。 (我不能一步一步从x到z,因为操作很复杂,这只是一个例子)

所以当我运行这个例子时,内存不足大概是因为x,y和z是都在范围内,他们都占有记忆。

所以我尝试以下方法:

def main(args:Array[String]) = { 
    val N = 10000000 
    val z = { 
      val y = { 
       val x = List(1 to N).flatten 
       println(x.slice(0,10)) 
       Thread.sleep(5000) 
       x 

      }.map(_*5) 

      println(y.slice(0,10)) 
      Thread.sleep(5000) 
      y 

    }.map(_+4) 
    println(z.slice(0,10)) 
    Thread.sleep(5000) 
} 

所以现在只有Z是在范围之内。所以大概x和y被创建,然后当它们超出范围时收集垃圾。但这不是发生的事情。相反,我再次用光了内存!

(注:我用java -Xincgc,但它并不能帮助)

问题:当我有足够的内存只有1大名单,可我不知用操纵它只是VAL的(即没有可变变量或ListBuffers),也许使用范围来强制gc?如果是这样,怎么样? 谢谢

+0

您将始终需要两个列表的内存。出于好奇,你有没有设置你的Java堆?考虑'阵列'? –

+0

没错,我总是需要2个列表的内存,这是我的。 但我不应该需要内存3列表,我没有。 你同意吗? 在任何情况下,由于x和y超出范围,为什么一旦VM发现内存不足并且变量不在范围内,它们就不会被垃圾回收? –

回答

8

你试过类似的东西吗?

val N = 10000000 
val x = List(1 to N).flatten.view // get a view 
val y = x.map(_ * 5) 
val z = y.map(_ + 4) 
println(z.force.slice(0, 10)) 

应该有助于避免了yz创建中间完整结构。

+1

嘿谢谢!这实际上很好地解决了这个问题!没有内存不足的错误。我必须在最后一个操作中包含一个“强制”,但它看起来像我可以在视图上执行任何数量的中间操作而不分配任何更多的内存。正是我想要的。 –

0

它是一个便宜的答案,但你尝试用更多的内存启动jvm吗?

例如

$ java的-X ... -Xmx设置最大Java堆大小

此外,GC可能不会帮助,因为它听起来像是你要在内存中的两个表在同一抓在过渡期间,他们都被引用。

3

看看使用view。它需要一个集合并延迟加载它,只在需要时计算值。它不构成中间集合:

scala> (1 to 5000000).map(i => {i*i}).map(i=> {i*2}) .toList 
java.lang.OutOfMemoryError: Java heap space 
     at java.lang.Integer.valueOf(Integer.java:625) 
     at scala.runtime.BoxesRunTime.boxToInteger(Unknown Source) 
     at scala.collection.immutable.Range.foreach(Range.scala:75) 
     at scala.collection.TraversableLike$class.map(TraversableLike.scala:194) 
     at scala.collection.immutable.Range.map(Range.scala:43) 
     at .<init>(<console>:8) 
     at .<clinit>(<console>) 
     at .<init>(<console>:11) 
     at .<clinit>(<console>) 
     at $print(<console>) 
     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
     at java.lang.reflect.Method.invoke(Method.java:597) 
     at scala.tools.nsc.interpreter.IMain$ReadEvalPrint.call(IMain.scala:704) 
     at scala.tools.nsc.interpreter.IMain$Request$$anonfun$14.apply(IMain.scala:920) 
     at scala.tools.nsc.interpreter.Line$$anonfun$1.apply$mcV$sp(Line.scala:43) 
     at scala.tools.nsc.io.package$$anon$2.run(package.scala:25) 
     at java.lang.Thread.run(Thread.java:662) 
scala> (1 to 5000000).view.map(i => {i*i}).view.map(i=> {i*2}) .toList 
res10: List[Int] = List(2, 8, 18, 32, 50, 72, ...