2011-12-27 8 views
4

私はScalaの遅延イテレータを使用しています。問題が発生しました。その後、私は何をしようとしている大きなファイルに読み込まれ、変換を行い、その結果書き出す:Scala Infinite Iterator OutOfMemory

object FileProcessor { 
    def main(args: Array[String]) { 
    val inSource = Source.fromFile("in.txt") 
    val outSource = new PrintWriter("out.txt") 

    try { 
     // this "basic" lazy iterator works fine 
     // val iterator = inSource.getLines 

     // ...but this one, which incorporates my process method, 
     // throws OutOfMemoryExceptions 
     val iterator = process(inSource.getLines.toSeq).iterator 

     while(iterator.hasNext) outSource.println(iterator.next) 

    } finally { 
     inSource.close() 
     outSource.close() 
    } 
    } 

    // processing in this case just means upper-cases every line 
    private def process(contents: Seq[String]) = contents.map(_.toUpperCase) 
} 

は、だから私は大きなファイルでのOutOfMemoryExceptionを取得しています。ストリームの頭を参照している場合は、Scalaの怠惰なストリームに遭遇する可能性があることはわかっています。ですから、この場合、process()の結果をイテレータに変換し、最初に返すSeqをスローアウェイしてください。

これがまだO(n)のメモリ消費を引き起こす理由は誰にも分かりますか?ありがとう!


更新

はFGEとhuynhjlに応じて、犯人かもしれない配列のように思えるが、私はなぜ知りません。例として、次のコードはうまく動作します(そして、私はSeqを使用しています)。

FGEで示唆したよう
object FileReader { 
    def main(args: Array[String]) { 

    val inSource = Source.fromFile("in.txt") 
    val outSource = new PrintWriter("out.txt") 
    try { 
    writeToFile(outSource, process(inSource.getLines.toSeq)) 
    } finally { 
    inSource.close() 
    outSource.close() 
    } 
} 

@scala.annotation.tailrec 
private def writeToFile(outSource: PrintWriter, contents: Seq[String]) { 
    if (! contents.isEmpty) { 
    outSource.println(contents.head) 
    writeToFile(outSource, contents.tail) 
    } 
} 

private def process(contents: Seq[String]) = contents.map(_.toUpperCase) 
+3

野生の推測: '.getLines.toSeq'? – fge

答えて

6

、イテレータを取り、.toSeqを削除するprocessを変更:このコードはないは、OutOfMemoryException例外を生成しません。 inSource.getLinesはすでにイテレータです。

Seqに変換すると、アイテムが記憶されます。私はイテレータをStreamに変換し、すべてのアイテムを記憶させると思います。

編集:それはより微妙です。プロセスの結果についてiteratorを呼び出して、Iterator.toSeq.iteratorに相当する処理を行っています。これにより、メモリ不足の例外が発生する可能性があります。

scala> Iterator.continually(1).toSeq.iterator.take(300*1024*1024).size 
java.lang.OutOfMemoryError: Java heap space 

https://issues.scala-lang.org/browse/SI-4835と同じ問題かもしれません。バグの最後に私のコメントを書き留めてください。これは個人的な経験からです。