从 PersistentQueue 中弹出的元素引用不会立即从队列中移除。这可能导致队列保留的元素比当前包含的元素多得多。
这发生是因为 PersistentQueue 使用两个 PersistentVector 来实现,一个用于头部,一个用于尾部。一旦头部为空,尾部向量将被转换为 ChunkedSeq(通过调用 seq)并放入头部。然而,ChunkedSeq 总是保留对整个起始向量的引用,即使它在 shrunk 时被 next 缩小。
示例,使用 clj-memory-meter
`
(require '[clj-memory-meter.core :as mm])
(def q clojure.lang.PersistentQueue/EMPTY)
(def strs (repeatedly 100000 #(String. (.toCharArray "Hello"))))
;; 使用 100k 个 "Hello" 字符串的队列
(mm/measure (into q strs))
=> "5.9 MB"
;; 缩小此类队列以仅包含 1 个元素
(nth (iterate pop (into q strs)) 99999)
=> ;; 一个包含一个元素的队列
;; 但它仍然占用 6 MB
(mm/measure (nth (iterate pop (into q strs)) 99999))
=> "5.9 MB"
`
也许,如果这种行为是预期的,它至少可以在文档的某个地方反映出来?考虑到 PQ 已经是隐藏的并且文档不充分。