2011-12-27 122 views
4

我在玩Scala的懶惰迭代器,並且遇到了一個問題。我正在試圖做的是在一個大文件讀取,做一個轉換,然後寫出來的結果是:Scala無限迭代器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。我知道如果你圍繞着Stream的頭部引用,你可能會和Scala的懶惰Streams發生衝突。所以在這種情況下,我會小心地將process()的結果轉換爲迭代器,並丟棄最初返回的Seq。

有誰知道爲什麼這仍然會導致O(n)內存消耗?謝謝!


更新

針對FGE和huynhjl,就好像序列可能是罪魁禍首,但我不知道爲什麼。作爲一個例子,下面的代碼工作正常(我在各地使用Seq)。此代碼產生一個OutOfMemoryException:

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 2011-12-27 02:28:15

回答

6

作爲暗示由FGE,修改process採取一個迭代並刪除.toSeqinSource.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。請注意我在錯誤結束時的評論,這是來自個人經驗。