如果我使用doseq
进行迭代但是保留第一个元素的一部分,我想了解延迟序列的行为。
(with-open [log-file-reader (clojure.java.io/reader (clojure.java.io/file input-file-path))]
; Parse line parse-line returns some kind of representation of the line.
(let [parsed-lines (map parse-line (line-seq log-file-reader))
first-item (first parsed-lines)]
; Iterate over the parsed lines
(doseq [line parsed-lines]
; Do something with a side-effect
)))
我不想保留任何列表,我只想对每个元素执行副作用。我相信没有first-item
就没有问题。
我的程序中存在内存问题,我认为可能在parsed-line
序列的开头保留对某些内容的引用意味着存储了整个序列。
这里定义的行为是什么?如果正在存储序列,是否有通用的方法来获取对象的副本并使序列的已实现部分被垃圾收集?
答案 0 :(得分:2)
序列保持在这里发生
...
(let [parsed-lines (map parse-line (line-seq log-file-reader))
...
文件中的行序列正在延迟生成和解析,但整个序列保留在let
的范围内。此序列在doseq
中实现,但doseq
不是问题,它不执行序列保持。
...
(doseq [line parsed-lines]
; Do something
...
您不一定关心let
中的序列保持,因为let
的范围有限,但这里可能是您的文件很大和/或您保持在let
的动态范围内{1}}暂时,或者在“执行某事”部分中返回包含它的闭包。
请注意,保留序列的任何给定元素(包括第一个元素)都不会保留序列。如果你认为头部是Prolog中“头部列表”中的第一个元素,那么头部控制这个词有点用词不当。问题是持续对序列的引用。
答案 1 :(得分:1)
一旦JVM成为java堆的一部分,JVM永远不会将内存返回给操作系统,除非你以不同的方式配置它,否则默认的最大堆大小非常大(通常是可用内存的1/4)。因此,如果您只是遇到模糊的问题,如“Gosh,这需要占用大量内存”,而不是“嗯,JVM抛出OutOfMemoryError”,您可能只是没有按照您希望的方式调整JVM法案。 partition-by
是一个 little 渴望,因为它一次在内存中保存一个或两个分区,但除非你的分区很大,否则你不应该用这个代码耗尽堆空间。尝试设置-Xmx100m
,或者您认为程序的合理堆大小,并查看是否有问题。