我是scala的新手,您想了解为什么会出现以下代码
在GC overhead limit exceeded
中,应采取哪些措施来避免它。
import scala.io.Source
import scala.annotation.tailrec
def getItems(file: Source): Stream[String] = {
@tailrec
def acc(it: Iterator[String],
item: String,
items: Stream[String]): Stream[String] = {
if(it.hasNext){
val line = it.next
line take 1 match {
case " " =>
acc(it, item + "\n" + line, items)
case "1" =>
acc(it, item, Stream.cons(item, items))
}
}
else {
Stream.cons(item, items)
}
}
acc(file.getLines(), "", Stream.Empty)
}
答案 0 :(得分:1)
您的代码有两个原因可能导致 OOM :
item
将递归添加文件长度,这可能会非常大,具体取决于您的文件大小。Stream
重复附加已累积的item
至Stream
,这也可能非常大,导致 OOM 。有一种方法可以通过使用延迟评估和Stream
而不使用memorization
来保存此方案。
答案 1 :(得分:0)
我试图弄清楚你实际上要做什么,但问题是你正在使用你的acc函数递归,直到你的输入文件没有更多的元素。这是一个非常简单的示例,它将迭代器转换为流。
def convert[T]( iter : Iterator[T] ) : Stream[T] =
if ( iter.hasNext ) {
Stream.cons( iter.next, convert( iter ) )
} else {
Stream.empty
}
此外,您将所有以空格开头的行追加到item
。我不知道您在输入中有多少这样的行,但如果所有行都以空格开头,如果您的输入文件有n个字符,则会使用(n^2)/2
个字符。但我不认为这就是你的递归失败的原因。
答案 2 :(得分:0)
Stream
实际上是一个漏洞抽象。它假装是Seq
,但如果流量巨大,则不能将其用作常规集合。
这是一篇关于流http://blog.dmitryleskov.com/programming/scala/stream-hygiene-i-avoiding-memory-leaks/的文章
在您的情况下,违反了规则“不在方法参数中存储Streams”(items
)。