您需要将字段自定义解析为更小、更紧凑的类型。如果您正在存储许多重复的字符串,请使用字符串规范化和重用重复字符串(共享引用)。典型的做法是使用在解析时共享引用。
我在这里发布了一个简短的演示项目,该项目采用了两种方法
- 使用spork.util.table(我旧的表格处理库),它基于持久结构,并使用我提到的技术
- 使用tech.ml.dataset,这是最近的一项工作,它利用了TableSaw表的实现,用于快速、内存高效的结构(可变的,但COW实现具有持久语义)。
这两种解决方案都可以很容易地处理大约300MB的TSV文件(默认堆大小约为2GB),尽管在实际情况中tech.ml.dataset的内存效率要高得多。
我还在放了一个版本,它可以复制您的测试输入(在一定程度上是猜测的,大约是1/3)。它显示了如何使用spork、tech.ml(目前尝试解析日期时失败),最后使用纯clojure函数手动处理。如果您希望最小化内存占用(和性能),则解析到原始数据类型是必要的。不幸的是,Java集合通常是装箱的(除数组外),因此您需要像FastUtils这样的工具或另一个原始数据类型集合。Clojure原始数据类型向量有点帮助,但它们仍然因为数组的字典(数组仅存在于叶子中)而承担引用开销。或者是如果您只是从文件中构建同质类型的密集数组,您可以构造原始数组并填充它。这将节省空间并且机械上兼容,尤其是在您使用浮点数进行数值计算并可以利用密集格式时。
底线是 —— 天真的解析,特别是当保留对字符串或装箱对象的引用时 —— 将需要巨大的堆,因为Java对象消耗内存。
注意:这仅适用于必须“保留”数据的情况……如果您可以对其进行折叠或其他流式计算,则可能无需爆堆即可使用天真解析任意数据集(例如,大于内存),因为JVM会在处理旧引用之后立即进行垃圾回收。
还有一些库可以用于这项任务,
以及最近通过libpython-clj的pandas包装器。
关于内存性能的注意事项:JVM 默认不会将内存释放回系统,所以它的内存使用量会“增长”到通过 -Xmx(默认我认为是 2GB)设置的极限,并且它似乎会停留在那里(即使经过垃圾回收周期)。如果您想了解实际使用的情况与预留的情况,您需要附加一个剖析器并查看堆使用情况(例如 jvisualvm)。