1

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意味着整个序列都被存储了。

这里定义的行为是什么?如果正在存储序列,是否有一种通用的方法来获取对象的副本并使序列的已实现部分能够被垃圾收集?

4

2 回答 2

2

序列保持发生在这里

...
(let [parsed-lines (map parse-line (line-seq log-file-reader))
...

文件中的行序列被延迟生成和解析,但整个序列被保留在let. 这个序列在 中实现doseq,但doseq不是问题,它不做序列保持。

...
(doseq [line parsed-lines]
 ; Do something
...

您不一定关心 a 中的序列保持,let因为范围let是有限的,但这里大概您的文件很大和/或您在动态范围内停留let了一段时间,或者可能返回包含它的闭包在 "做某事”部分。

请注意,保持序列的任何给定元素,包括第一个元素,都不会保持序列。如果您将 head 视为 Prolog 中“列表的头部”中的第一个元素,那么术语 head-holding 有点用词不当。问题在于对序列的引用。

于 2014-01-24T13:26:13.407 回答
1

一旦 JVM 成为 Java 堆的一部分,它就永远不会将内存返回给操作系统,除非您对其进行不同的配置,否则默认的最大堆大小非常大(通常是可用 RAM 的 1/4)。因此,如果您只是遇到诸如“天哪,这会占用大量内存”之类的模糊问题,而不是“嗯,JVM 抛出了 OutOfMemoryError”,那么您可能只是没有按照您想要的方式调整 JVM行为。partition-by有点急切,因为它一次在内存中保存一个或两个分区,但除非你的分区很大,否则你应该用这段代码耗尽堆空间。尝试设置-Xmx100m,或者任何你认为对你的程序来说合理的堆大小,看看你是否有问题。

于 2014-01-25T21:12:40.997 回答