awh*_*awh 5 clojure out-of-memory
我正在关注algo-class.org课程,其中一个编程作业提供了一个格式如下的文件:
1 2
1 5
2 535
Run Code Online (Sandbox Code Playgroud)
...
有超过500万这样的行,我想在文件中读取并将其转换为整数向量的向量,如下所示:[[1 2] [1 5] [2 535] ...].
(defn to-int-vector [s]
(vec (map #(Integer/parseInt %) (re-seq #"\w+" s))))
(def ints (with-open [rdr (clojure.java.io/reader "<file>")]
(doall (map to-int-vector (line-seq rdr)))))
Run Code Online (Sandbox Code Playgroud)
所以我相信这样,我不是将整个文件保存在内存中,而只生成一个大的整数向量.但是我从中得到了OutOfMemoryError.我尝试通过运行rand-int来生成相同大小和相同格式的向量,并且工作正常.
看起来内存问题是由生成的临时对象引起的?clojure处理这样一个案例的理想方式是什么?
更新:
是的,我意识到我持有整个整数向量.我已经提高了堆大小,现在可以了.我很感兴趣的是,一个载体和500万个元素(1000万个整数)可以占用大量内存 - 我必须为jvm分配3g.有没有其他方法可以记住内存?
你不会相信实现的懒惰seq强加了多少开销.我在64位操作系统上测试了它:它类似于120字节.这对于每个懒惰的seq成员来说都是纯粹的开销.另一方面,向量具有相当低的开销,并且在给定足够大的向量的情况下基本上与Java数组相同.因此,尝试更换doall
用vec
.
让我们看看你花了多少内存而没有开销.你有5e6对整数 - 这是5e6 x 8 = 40 MB.您可以通过使用short来节省并节省50%(我重复一遍 - 这不计算父集合的开销,并且持有该对的每个向量实例都有自己的开销).
保存的下一步是为外部集合和对使用原始数组.它仍然是一个非常实用的解决方案,因为阵列是可选的并且与语言很好地集成.要做到这一点,你只需要更换的两次出现vec
用to-array
.
UPDATE
之间的区别Integer
,并Short
没有那么大,由于两者仍然完全成熟的对象.使用short-array
(或int-array
)而不是将数字对存储为原始数组可以节省更多to-array
.
in将确保整个结果存储在内存中
,该内存至少与文件一样大,因为每行上的数字都存储在一个集合中,在本例中是一个 vec,它也占用空间def
。(def ints
另外默认情况下java会拒绝使用计算机中的所有内存,你可能需要设置maxHeapSize参数。
如果您从一个新的 repl 开始(尚未保存任何大列表),您是否仍然会耗尽内存?
归档时间: |
|
查看次数: |
629 次 |
最近记录: |