首页 > 解决方案 > 如何以内存高效的方式使用 Kotlin 的序列和 lambda

问题描述

所以我正在编写一些既需要内存效率又需要快速的代码。我已经在 java 中有一个工作参考,但正在用 kotlin 重写它。

我基本上需要加载很多 csv 文件并将它们加载到树中一次,然后在加载后重复遍历它们。

我最初使用序列编写了整个内容,但发现它会导致 GC 反复飙升。

我不能真正分享这段代码,但想知道你们是否知道会导致这种情况发生的原因。

我很乐意根据您的需要添加细节,但这是我的基本模式。

步骤1:inputStream -> csvLines: List<String>

第2步:csvLines.drop(x).fold(emptySequence()) -> callOtherFunctionWithFold -> callOtherFunctionWithFold -> Sequence<OutputObjects>

我将 csvLines 保留为单独的列表,因为我正在根据我需要的规则访问特定的行。

第三步:Sequence<OuputObjects> -> nodes

结果是功能性的,但是与仅使用数组列表并就地修改它们的 java 等效代码相比,此代码的内存效率和性能要低得多。

在查看了 visualvm 输出后,我创建了大量的 kotlin.*.ArrayIterators。看起来我每次使用 lamda 时都会创建一个。

那么我能做些什么来提高效率呢?我虽然序列应该减少对象创建的惰性,但看起来我正在做的事情破坏了它这样做的能力。

GC 运行或一般运行后是否会重新评估序列?如果是这样,那会使它们不适合在启动时加载的对象中使用,对吗?

视觉虚拟机运行

标签: kotlinlambdasequencememory-footprint

解决方案


要使用 Kotlin 序列,您需要从asSequence()

csvLines.asSequence()
    .drop(x)
    .fold(...)
    ...

如果你忽略它,它会使用 Collection 函数,而不是在每个函数之后创建一个新的(中间)集合。


推荐阅读