clojure - 持久收集是垃圾收集吗?

标签 clojure

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

函数 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/

相关文章:

clojure - Clojure 中的速率限制 core.async channel

java在maven和eclipse中与clojure混合

ios - iOS 开发

clojure - 识别 Clojure 中的不纯函数

authentication - 用Friend登录,从服务器端?

clojure - Compojure route 的逗号

clojure - 用于无 UI 网络服务的 Compojure 或 Noir?

for-loop - `for` 在此递归 Clojure 代码中如何工作?

clojure - core.logic matche、defne 模式匹配构造使用什么语法?

testing - 函数调用中的测试或 clojure 中的语句未运行