2011-11-25 38 views
5

Tôi có một danh sách rất lớn các số, trải qua rất nhiều thao tác toán học. Tôi chỉ quan tâm đến kết quả cuối cùng. Để mô phỏng hành vi này, hãy xem mã ví dụ của tôi bên dưới:Các vấn đề về phạm vi và bộ nhớ trong 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) 
} 
    } 

Vì vậy x là danh sách rất lớn. Tôi chỉ quan tâm đến kết quả z. Để có được z, trước tiên tôi phải thao tác toán học x để có được y. Sau đó, tôi thao tác y để có được z. (Tôi không thể đi từ x đến z trong một bước, bởi vì các thao tác khá phức tạp. Đây chỉ là một ví dụ.)

Vì vậy, khi tôi chạy ví dụ này, tôi hết bộ nhớ có lẽ vì x, y và z tất cả trong phạm vi và tất cả đều chiếm bộ nhớ.

Vì vậy, tôi thử như sau:

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

Vì vậy, bây giờ chỉ z là trong phạm vi. Vì vậy, có lẽ x và y được tạo ra và sau đó rác thu thập được khi chúng đi ra khỏi phạm vi. Nhưng đây không phải là những gì xảy ra. Thay vào đó, tôi lại hết bộ nhớ!

(Lưu ý: Tôi sử dụng java -Xincgc, nhưng nó không giúp)

Câu hỏi:. Khi tôi có bộ nhớ đủ để chỉ có 1 danh sách lớn, tôi có thể bằng cách nào đó vận dụng nó chỉ sử dụng val (tức là không có có thể thay đổi các vars hoặc ListBuffers), có thể dùng scoping để ép gc? Nếu vậy, làm thế nào? Cảm ơn

+0

Bạn sẽ luôn cần bộ nhớ cho hai danh sách. Trong tò mò, bạn đã thiết lập vùng heap Java của mình chưa? Được coi là 'Array'? –

+0

Đúng, tôi sẽ luôn cần bộ nhớ cho 2 Danh sách mà tôi có. Nhưng tôi không cần bộ nhớ cho 3 danh sách mà tôi không có. Bạn có đồng ý không? Trong mọi trường hợp, kể từ khi x và y đi ra khỏi phạm vi, tại sao họ không thu thập rác một khi VM nhận ra ngắn của nó trên bộ nhớ và các biến không nằm trong phạm vi? –

Trả lời

8

Bạn đã thử một cái gì đó như thế này?

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

Nó sẽ giúp tránh việc tạo ra cấu trúc đầy đủ trung gian cho yz.

+1

Xin cảm ơn! Điều đó thực sự khắc phục vấn đề rất độc đáo !! Không có lỗi bộ nhớ. Tôi phải bao gồm một "lực lượng" vào hoạt động cuối cùng, nhưng có vẻ như tôi có thể thực hiện bất kỳ số hoạt động trung gian nào trên màn hình mà không cần phân bổ thêm bộ nhớ nào nữa. Chính xác những gì tôi muốn. –

0

Câu trả lời rẻ tiền của nó, nhưng bạn đã thử bắt đầu jvm với nhiều bộ nhớ hơn chưa?

ví dụ:

$ java -X ... -Xmx thiết Java tối đa kích thước heap

Ngoài ra, GC có lẽ sẽ không giúp đỡ, bởi vì nó có vẻ như bạn đang bị bắt với hai danh sách trong bộ nhớ tại cùng thời gian trong quá trình chuyển đổi và cả hai đều được tham chiếu.

3

Nhìn vào sử dụng view. Phải mất một bộ sưu tập và tải nó một cách lười biếng, chỉ tính toán giá trị khi được yêu cầu. Nó không tạo thành bộ sưu tập trung gian:

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, ... 
Các vấn đề liên quan