gpt4 book ai didi

Scala 可迭代内存泄漏

转载 作者:行者123 更新时间:2023-12-04 15:01:42 24 4
gpt4 key购买 nike

我最近开始玩 Scala 并遇到了以下问题。下面是 4 种不同的方法来遍历文件的行,做一些事情,并将结果写入另一个文件。这些方法中的一些像我想象的那样工作(尽管使用了大量内存来这样做),而一些则无休止地消耗内存。

这个想法是将 Scala 的 getLines Iterator 包装为一个 Iterable。我不在乎它是否多次读取文件 - 这就是我希望它做的。

这是我的重现代码:

class FileIterable(file: java.io.File) extends Iterable[String] {
override def iterator = io.Source.fromFile(file).getLines
}

// Iterator

// Option 1: Direct iterator - holds at 100MB
def lines = io.Source.fromFile(file).getLines

// Option 2: Get iterator via method - holds at 100MB
def lines = new FileIterable(file).iterator

// Iterable

// Option 3: TraversableOnce wrapper - holds at 2GB
def lines = io.Source.fromFile(file).getLines.toIterable

// Option 4: Iterable wrapper - leaks like a sieve
def lines = new FileIterable(file)

def values = lines
.drop(1)
//.map(l => l.split("\t")).map(l => l.reduceLeft(_ + "|" + _))
//.filter(l => l.startsWith("*"))

val writer = new java.io.PrintWriter(new File("out.tsv"))
values.foreach(v => writer.println(v))
writer.close()

它正在读取的文件是 ~10GB 和 1MB 行。

前两个选项使用恒定的内存量 (~100MB) 迭代文件。这是我所期望的。这里的缺点是迭代器只能使用一次,并且它使用 Scala 的按名称调用约定作为伪可迭代。 (作为引用,等效的 c# 代码使用 ~14MB)

第三个方法调用在 TraverableOnce 中定义的 toIterable。这个工作,但它使用大约 2GB 来做同样的工作。不知道内存的去向,因为它无法缓存整个 Iterable。

第四个是最令人震惊的 - 它立即使用所有可用内存并抛出 OOM 异常。更奇怪的是,它对我测试过的所有操作都这样做:删除、映射和过滤。看看这些实现,它们似乎都没有保持多少状态(尽管下降看起来有点可疑 - 为什么它不只计算项目?)。如果我不做任何操作,它工作正常。

我的猜测是它在某个地方维护对所读取的每一行的引用,尽管我无法想象如何。在 Scala 中传递 Iterables 时,我看到了相同的内存使用情况。例如,如果我采用 case 3 (.toIterable) 并将其传递给将 Iterable[String] 写入文件的方法,我会看到同样的爆炸。

有任何想法吗?

最佳答案

请注意 ScalaDoc of Iterable 说:

Implementations of this trait need to provide a concrete method with signature:

  def iterator: Iterator[A]

They also need to provide a method newBuilder which creates a builder for collections of the same kind.



由于您没有为 newBuilder 提供实现,您将获得默认实现,它使用 ListBuffer并因此尝试将所有内容放入内存中。

您可能想要实现 Iterable.drop作为
def drop(n: Int) = iterator.drop(n).toIterable

但这会破坏集合库的表示不变性(即 iterator.toIterable 返回 Stream ,而您希望 List.drop 返回 List 等 - 因此需要 Builder 概念)。

关于Scala 可迭代内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12504917/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com