您需要将字段自定义解析为更小、更紧凑的类型。如果您存储了一堆重复的字符串,请使用字符串规范化的方式重用重复的字符串(共享引用)。通常的做法是在解析时使用 字符串池 来共享引用。
我在这里发布了一个简短的演示项目 这里,介绍了这个做法的两种方法
- 使用 spork.util.table(我以前的数据表杂凑库),它基于持久结构,并使用了我所提到的技术
- 使用 tech.ml.dataset,这是一项利用 TableSaw 表实现进行快速、内存高效结构(可变的,但COW实现用于持久语义)的最新努力。
这两个解决方案都可以很好地处理一个约300MB的tsv文件,使用默认堆(大约2GB),尽管tech.ml.dataset在实际情况中要显著节省内存。
我还将一个版本放入 测试,用于复制您的测试输入(在一定程度上,我猜测了有多少空值,大约为1/3)。它显示了使用spork、tech.ml(目前尝试解析日期时失败)的方法,最后使用纯clojure函数手动处理。如果您想要最小的内存占用(和性能),则必须解析为原语。不幸的是,Java集合通常被装箱(除了数组),所以您需要像FastUtils或其他原语支持的集合一样的东西。Clojure原语支持向量有所帮助,但它们仍然因数组的trie(数组只位于叶子)而产生引用开销。或者,如果您只是从文件中构建一个由同质类型构成的密集数组,可以构造一个原始数组并填充它。这将节省空间并机械上一致,尤其是如果您使用这些浮点数进行数值运算并可以利用密集格式。
总之,- 原始解析,尤其是保留字符串或装箱对象的引用 - 由于Java对象占用内存较多,需要巨大的堆。
注意:这仅适用于您必须“保留”数据的情况......如果您可以对其进行reduce操作或其他流式计算,则可以尽可能避免使用原始解析进行任意大数据集(例如大于内存的)而不破坏堆,因为JVM将在您处理完后立即回收旧引用。
还有一些其他有用的库可以用于这种类型的任务 iota,
以及通过libpython-clj实现的最新pandas包装器panthera。
内存性能提示:JVM默认不会将内存释放回系统,因此它的内存使用量看起来会“增长”到由-Xmx参数设置的极限(默认为2GB左右),并且似乎会停留在那里(即使在GC周期之后)。如果您想了解实际使用量和预留量,您需要附加一个性能分析器并查看堆使用统计信息(例如jvisualvm)。