最小化例子
`
(fn foo [x]
(if true
(^:once fn* []
;; x is not cleared here
x)))
`
这意味着 Clojure 编译器将每个在循环或 try/catch 表达式内部使用的局部引用内部提升到 FNONCE,在条件分支中,现在无法清除。
作为一个具体示例,如 Slack 中报道的,
`
;; 这导致 OOM
(defn test1 [x]
(if true
(do
(try (doseq [_ x] _))
1)
0))
(test1 (take 1000000 (range)))
;; 这不会导致 OOM
(defn test2 [x]
(do
(try (doseq [_ x] _))
1))
(test2 (take 1000000 (range)))
`
方法:如果函数为 ^:once 并且存在一个现有的清除帧,则不要设置一个新的清除帧
补丁:0001-CLJ-2145-fix-clearing-of-locals-closed-over-by-a-FNO.patch