Clojure 持久性收集是垃圾收集吗?

Clojure 持久性收集是垃圾收集吗?,clojure,Clojure,如果我持有对持久收集的一部分的e引用,那么整个收集可以被垃圾收集吗?我理解正确吗 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=&

如果我持有对持久收集的一部分的e引用,那么整个收集可以被垃圾收集吗?我理解正确吗

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)
我已经听说过头部保留,但这似乎有点普遍,不是吗

我想了解的是如何使用大变身系列。我希望收集的大部分会随着时间的推移而改变,原则上可以对大部分进行垃圾收集,但不是全部


有没有一个标准的方法来解决这个问题?

这些问题可以用惰性序列来解决。在您的例子中,您使用了
vec
函数,它通过遍历
range
函数生成的每个元素(range返回一个惰性序列),在内存中实际创建了一个向量

下面的代码(如果没有
vec
调用,则不会出现内存问题)

更新


当您使用
vec
调用时,内存中的所有元素都将被保留,而不是由GC收集,因为这些元素被从函数
gctest
返回的序列对象引用(并且是必需的),因此它可以获取必需的元素(即跳过100个元素并获取5个元素)当序列对象被请求元素时。

标准GC规则保持不变:只要保留对集合一部分的引用,所有可从引用访问的对象都将保留在内存中。因此,只有可从您的引用中访问的收集部分将被保留,其余部分将被收集。特别是,如果参考100个元素列表中的最后50个元素,将收集前50个元素,其余元素将保留在内存中

但是,在您的情况下,将保留从第100个开始的每个集合的所有元素。其原因是懒惰的评估。函数
take
生成5个元素的惰性序列。惰性序列对象本身不是真正的序列,而是特殊的生成器对象(虽然它不是Clojure的,而是Python的术语)。当您需要惰性序列的元素时,generator对象生成并返回它。但如果您不请求元素,生成器只保留对生成元素所需的所有对象的引用

在您的示例中,创建大向量并从中请求5个元素,然后将结果保存到变量
a
b
c
,等等。Clojure生成大向量和生成器对象,指向第100个元素。对集合本身的引用丢失,但对生成器对象的引用保存在顶层。您永远不会计算生成器对象,因此永远不会生成真正的5元素序列。REPL指的是变量
a
b
c
,等等,这些变量指的是生成器对象,生成器对象指的是生成真实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 

没有什么好回忆的!Vars
a
b
c
等现在存储5个元素的真实列表,因此不再引用大型集合,因此可以收集它们

抱歉,该功能仅用于演示。我编辑这个问题是为了让大家更容易理解。Ankur-我认为使用vec是问题的关键:该向量的哪些元素将被保留?该向量的所有元素都将被保留,因为它是从
gctest
返回的惰性Sequeuence对象所需要的,所以我曾经太懒了。伟大的
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