当我定义一个在外部作用域中捕获其某些变量的函数时,如下所示,Clojure(在 JVM 主机上)实际上如何存储捕获的环境?
(let [small-datastructure (calculate-small-thing)
large-datastructure (calculate-large-thing)]
(if *feeling-lucky*
(fn capturing-closure [] (do-other-thing small-datastructure))
(use-data large-datastructure))
特别是,函数
capturing-closure
仅引用small-datastructure
,而不引用large-datastructure
。当我从此代码返回 capturing-closure
时,large-datastructure
是否仍会被 capturing-closure
引用,还是会被释放到垃圾回收中?
对于如何准确衡量这一点,我愿意接受直接答案或建议。
回答我自己的问题——尽管我仍然很欣赏基于对 Clojure/JVM 内部结构的深入了解的答案!
我做了一个小实验,使用
(System/gc)
来强制GC,并使用弱引用来检查GC后对象是否仍然存在于堆上:
(ns gc-test
(:import [java.lang.ref WeakReference]))
(defn calculate-small-thing [] (vec (range 10)))
(defn calculate-large-thing [] (vec (range 10000000)))
(def closure-use (atom nil))
(defn test-closure-gc []
(dotimes [i 10]
(println "Test iteration:" i)
(let [[weak-small-ref, weak-large-ref]
(let [small-datastructure (calculate-small-thing)
weak-small-ref (WeakReference. small-datastructure)
large-datastructure (calculate-large-thing)
weak-large-ref (WeakReference. large-datastructure)
capturing-closure (fn [] (reduce + small-datastructure))]
;; Store the closure to prevent it from being garbage collected
(reset! closure-use capturing-closure)
;; Return our weak references
[weak-small-ref weak-large-ref])]
;; Force garbage collection
(System/gc)
;; Sleep briefly to allow GC to complete
(Thread/sleep 100)
;; Sanity-check that small-datastructure is not collected
(println "Is small-datastructure collected?"
(nil? (.get weak-small-ref)))
;; Check if large-datastructure has been garbage collected
(println "Is large-datastructure collected?"
(nil? (.get weak-large-ref))))))
;; Run the test
(test-closure-gc)
输出显示
small-datastructure
仍按预期被引用,并且 large-datastructure
得到可靠收集:
Test iteration: 0
Is small-datastructure collected? false
Is large-datastructure collected? true
Test iteration: 1
Is small-datastructure collected? false
Is large-datastructure collected? true
Test iteration: 2
Is small-datastructure collected? false
Is large-datastructure collected? true
Test iteration: 3
Is small-datastructure collected? false
Is large-datastructure collected? true
Test iteration: 4
Is small-datastructure collected? false
Is large-datastructure collected? true
Test iteration: 5
Is small-datastructure collected? false
Is large-datastructure collected? true
Test iteration: 6
Is small-datastructure collected? false
Is large-datastructure collected? true
Test iteration: 7
Is small-datastructure collected? false
Is large-datastructure collected? true
Test iteration: 8
Is small-datastructure collected? false
Is large-datastructure collected? true
Test iteration: 9
Is small-datastructure collected? false
Is large-datastructure collected? true