2011-12-27 72 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。请注意我在错误结束时的评论,这是来自个人经验。