2011-11-25 3 views
5

Ho una lista molto grande di numeri, che subiscono molta manipolazione matematica. Mi interessa solo il risultato finale. Per simulare questo comportamento, vedere il seguente codice di esempio:Scope e problemi di memoria in Scala

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) 
} 
    } 

Quindi x è un elenco molto grande. Mi interessa solo il risultato z. Per ottenere z, prima devo manipolare matematicamente x per ottenere y. Quindi maneggio y per ottenere z. (Non posso andare da x a z in un solo passaggio, perché le manipolazioni sono piuttosto complicate.Questo è solo un esempio.)

Così quando eseguo questo esempio, esaurisco la memoria presumibilmente perché x, yez sono tutto in ambito e tutti occupano memoria.

quindi cerco il seguente:

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) 
} 

Così ora solo z è portata. Quindi presumibilmente x e y vengono creati e quindi i garbage collection quando escono dal campo di applicazione. Ma questo non è quello che succede. Invece, di nuovo a corto di memoria!

(Nota: io sto usando Java -Xincgc, ma non aiuta)

. Domanda: Quando ho memoria adeguata per solo 1 elenco di grandi dimensioni, posso in qualche modo manipolarla utilizzando solo di val (cioè non mutable vars o ListBuffers), forse usando l'ambito per forzare gc? Se é cosi, come ? Grazie

+0

Avrete sempre bisogno di memoria per due elenchi. Per curiosità, hai impostato il tuo heap Java? Considerato 'Array's? –

+0

Vero, avrò sempre bisogno di memoria per 2 elenchi, cosa che ho. Ma non dovrei avere bisogno di memoria per 3 liste, che non ho. Sei d'accordo? In ogni caso, dato che x e y escono dall'ambito di applicazione, perché non vengono raccolti dati inutili una volta che la VM realizza il suo cortocircuito sulla memoria e le variabili non sono nel campo di applicazione? –

risposta

8

Hai provato qualcosa del genere?

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)) 

dovrebbe aiutare evitando di creare la struttura completa intermedio per y e z.

+1

Ehi, grazie! Questo risolve davvero il problema molto bene !! Nessun errore di memoria insufficiente. Devo includere una "forza" sull'ultima operazione, ma sembra che posso fare qualsiasi numero di operazioni intermedie sulla vista senza allocare altra memoria. Esattamente quello che volevo. –

0

È una risposta economica, ma hai provato ad avviare la jvm con più memoria?

ad es.

$ java -X ... -Xmx impostare la massima dimensione heap Java

Inoltre, GC, probabilmente non aiuterà, perché suona come stai essere scoperti con due liste in memoria allo stesso tempo durante la transizione e sono entrambi referenziati.

3

Guardare utilizzando view. Prende una raccolta e la carica pigramente, calcola il valore solo quando richiesto. Non costituisce una raccolta intermedia:

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, ...