如果在运行时替换函数,会 Clojure/JVM GC 旧代码吗?

If you replace functions at runtime, will Clojure/JVM GC old code?

如果经常在运行时替换函数,the way this poster wanted to do for the purposes of ,会不会Clojure/JVM GC旧代码?

有疑问问电脑!我写了一个快速测试:

(ns tst.demo.core
  (:use demo.core tupelo.core tupelo.test))
  
(defn create-fn
  [n]
  (let [fname   (symbol (format "add-%d" n))
        body    (vector '[x] (list '+ n 'x))
        fn-form (apply list 'clojure.core/defn fname body)
        fn-ref  (eval fn-form)]
    fn-ref))

(defn create-and-call-fn
  [n]
  (let [fn-ref (create-fn n)
        fn-result (fn-ref 3)]
    (when-not (= (+ 3 n) fn-result)
      (throw (ex-info "bad result" (vals->map n fn-result))))))


(dotest
  (let [f5 (create-fn 5)
        f5-result (f5 3)]
    (is= 8 f5-result))
  (dotimes [i 99999]
    (when (zero? (mod i 100)) (spyx i))
    (create-and-call-fn i)))

创建多达 10 万个函数后,它仍然有效。 YMMV!


以上是根据this template project.

答案是肯定的,生成的代码应该在将来的某个时候被收集。什么时候没有指定;它可能发生得晚,也可能永远不会发生。

另一件需要注意的事情是(特别是在使用来自另一个 eval 的代码时)是您在生成的代码中是否有循环引用以防止它们被卸载。通常,当一个 ClassLoader 被释放时,它的所有 classes 也会被释放——并且 JVM 之上的一些 interpreted/JITd 语言使用它来允许代码被回收。当 classes 被卸载时,任何编译的代码也会被丢弃——但是如果你有一个 class 的实例的引用 classloader (比如,在 ThreadLocalStorage 中)然后它将固定实例,然后是 class,然后是 classloader,所以它们可能仍然会泄漏。