2011-11-25 45 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, ...