7

Scala の例で質問しますが、命令型と関数型のハイブリッド スタイルを許可する他の言語に影響を与える可能性があります。

以下に短い例を示します ( UPDATED、以下を参照)。

def method: Iterator[Int] {
    // construct some large intermediate value
    val huge = (1 to 1000000).toList        
    val small = List.fill(5)(scala.util.Random.nextInt)
    // accidentally use huge in a literal
    small.iterator filterNot ( huge contains _ )    
}

iterator.filterNotでは怠惰に動作します。これは素晴らしいことです! その結果、返されたイテレータが多くのメモリを消費しないことが期待されます (実際、O(1))。しかし悲しいことに、私たちはひどい間違いを犯してしまいました:filterNotは遅延しているため、関数literal への参照を保持していますhuge contains _

したがって、メソッドは実行中に大量のメモリを必要とし、そのメモリはメソッドの終了直後に解放できると考えていましたが、実際には、返された を忘れるまでメモリはスタックしIteratorます。

(私はちょうどそのような間違いを犯しました。追跡するのに長い時間がかかりました!ヒープダンプを見ると、そのようなものを見つけることができます...)

この問題を回避するためのベスト プラクティスは何ですか?

唯一の解決策は、スコープの終わりを生き延び、中間変数をキャプチャした関数リテラルを注意深くチェックすることです。非厳密なコレクションを構築してそれを返すことを計画している場合、これは少し厄介です。この問題を回避し、適切なコードを記述できるようにする、Scala 固有またはその他の優れたトリックを考えられる人はいますか?

更新:以下の huynhjl の回答が示すように、私が以前に示した例は愚かでした。それは:

def method: Iterator[Int] {
    val huge = (1 to 1000000).toList // construct some large intermediate value
    val n = huge.last                // do some calculation based on it
    (1 to n).iterator map (_ + 1)    // return some small value 
}

実際、これらの仕組みが少し理解できたので、それほど心配していません。

4

1 に答える 1

5

テストケースを単純化しすぎていませんか?これが私が実行するものです:

object Clos {
  def method: Iterator[Int] = {
    val huge = (1 to 2000000).toList
    val n = huge.last
    (1 to n).iterator map (_ + 1)
  }

  def gc() { println("GC!!"); Runtime.getRuntime.gc }

  def main(args:Array[String]) {
    val list = List(method, method, method)
    list.foreach(m => println(m.next))
    gc()
    list.foreach(m => println(m.next))
    list.foreach(m => println(m.next))
  }
}

正しく理解していればmain、呼び出し後もイテレータを使用しているためgc()、JVMはオブジェクトを保持しhugeます。

これが私がそれを実行する方法です:

JAVA_OPTS="-verbose:gc" scala -cp classes Clos

これは、最後に印刷されるものです。

[Full GC 57077K->57077K(60916K), 0.3340941 secs]
[Full GC 60852K->60851K(65088K), 0.3653304 secs]
2
2
2
GC!!
[Full GC 62959K->247K(65088K), 0.0610994 secs]
3
3
3
4
4
4

したがって、hugeオブジェクトが再利用されたかのように見えます...

于 2010-10-18T06:22:39.130 に答える