如果我持有对持久集合的一部分的引用,整个集合是否可以被垃圾收集?我理解正确吗?
函数 gctest 只是为了测试集合的行为。
(defn gctest
"A shot about testing the gc-ability of persistent thingies."
[n]
(take 5 (drop 100 (vec (range n)))))
main=> (def a (gctest 1e7))
main=> (def b (gctest 1e7))
main=> (def c (gctest 1e7))
main=> (def d (gctest 1e7))
main=> (def e (gctest 1e7))
main=> (def f (gctest 1e7))
main=> (def g (gctest 1e7))
OutOfMemoryError GC overhead limit exceeded clojure.lang.ArrayChunk.dropFirst (ArrayChunk.java:54)
我已经听说过头部保留,但这似乎更一般,不是吗?
我想了解的是如何使用大变化的集合。我预计大部分集合会随着时间的推移而变化,原则上大部分可以被垃圾收集,但不是全部。
有没有标准的方法来处理这个问题?
最佳答案
标准 GC 规则仍然存在:只要您保留对集合的一部分的引用,所有可从您的引用访问的对象都将保留在内存中。所以仅部分 收藏 可访问 从您的引用将 保持 ,其余的将被收集。特别是,如果您引用 100 个元素列表的最后 50 个元素,前 50 个元素将被收集,其余的将保留在内存中。
但是,在您的情况下,从第 100 个开始的每个集合的所有元素都将保留。原因是懒惰评估 .功能 take
产生(在您的情况下)5 个元素的惰性序列。惰性序列对象本身并不是真正的序列,而是特殊的 生成器对象 (虽然它不是 Clojure 的,而是 Python 的术语)。当您需要惰性序列元素时,生成器对象会生成并返回它。但是,如果您不要求元素,生成器只会保留对生成元素可能需要的所有对象的引用。
在您的示例中,您创建大向量并从中获取 5 个元素,然后将结果保存到变量 a
, b
, c
等。Clojure 制作大向量和生成器对象,指向第 100 个元素。对集合本身的引用丢失,但对生成器对象的引用保存在顶层。您永远不会评估生成器对象,因此永远不会制作真正的 5 元素序列。 REPL 指的是变量 a
, b
, c
等,这些vars指的是生成器对象,生成器对象指的是它们产生真正的5元素序列所需的集合。因此,所有集合的所有元素(可能是其中的前 100 个除外)都必须留在内存中。
另一方面,如果您评估生成器对象 ,它们将产生真正的 5 个元素序列,并忘记对集合其余部分的引用。尝试这个:
user> (def a (gctest 1e7))
#'user/a
user> (println a)
(100 101 102 103 104)
nil
user> (def b (gctest 1e7))
#'user/b
user> (println b)
(100 101 102 103 104)
nil
user> (def c (gctest 1e7))
#'user/c
user> (println c)
(100 101 102 103 104)
nil
user> (def d (gctest 1e7))
#'user/d
user> (println d)
(100 101 102 103 104)
nil
user> (def e (gctest 1e7))
#'user/e
user> (println e)
(100 101 102 103 104)
nil
user> (def f (gctest 1e7))
#'user/f
user> (println f)
(100 101 102 103 104)
nil
user> (def g (gctest 1e7))
#'user/g
user> (println g)
(100 101 102 103 104)
nil
user> (def h (gctest 1e7))
#'user/h
user> (println h)
(100 101 102 103 104)
nil
user> (def i (gctest 1e7))
#'user/i
user> (println i)
(100 101 102 103 104)
nil
没有 OutOfMemory!变量
a
, b
, c
等现在存储 5 个元素的真实列表,因此不再有对大型集合的引用,因此可以收集它们。
关于clojure - 持久收集是垃圾收集吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11037477/