请在2024年 Clojure 状态调查!中分享您的想法。

欢迎!有关此如何工作的一些更多信息,请参阅关于页面。

0 投票
编译器

编译引用未加载(或未初始化)类的函数时,会触发其init静态。当init静态加载clojure代码时,一些常量(我认为是源代码)会泄露到正在编译的函数的常量池中。

因为生成的函数的静态init超过64K,所以它防止了CCW在某些环境中(Rational)工作。

重现步骤

加载leak.main命名空间,并运行注释中的代码:第一个函数有15个额外的字段,尽管它与第二个函数完全相同。

`
(ns leak.main)

(defn first-to-load []
leak.Klass/foo)

(defn second-to-load []
leak.Klass/foo)

(comment
=> (map (comp count #(.getFields %) class) [first-to-load second-to-load])
(16 1)
)
`

`
package leak;

import clojure.lang.IFn;
import clojure.lang.RT;
import clojure.lang.Symbol;

public class Klass {
static {

RT.var("clojure.core", "require").invoke(Symbol.intern("leak.leaky"));

}
public static IFn foo = RT.var("leak.leaky", "foo");
}
`

`
(ns leak.leaky)

(defn foo
"Some doc"
[]
"hello")

(def unrelated 42)
`

https://gist.github.com/cgrand/5dcb6fe5b269aecc6a5b#file-main-clj-L10

补丁: clj-1620-v5.patch

33 答案

0 投票

评论由:bronsa 发布

实际上,Ghadi 是对的,实际上用 (:foo {}) 替换 thunk-fail.core 的整个主体就足够了。

这似乎表明问题出在 AOT(再)编译顶层关键字查找位置,我的猜测是,出于某种原因,此补丁阻止了正确生成 __init 静态初始化器。

0 投票

评论由:bronsa 发布

我仍然完全没有头绪 lean compile 在做什么,但我已经解决了问题。
更新的补丁在评估期间只绑定适当的变量(如果已经绑定)。

0 投票
by

评论者:alexmiller

现在在绑定映射中使用transients是否值得呢?

0 投票
by

评论由:bronsa 发布

有道理,已经更新补丁使用transient映射。

0 投票
by

评论者:michaelblume

我们能否添加一个测试,在v2补丁存在的情况下会失败?最好是独立于CLJ-1544补丁?我可以尝试自己写一个,但我对Clojure编译器内部不熟悉。

0 投票
by

评论由:bronsa 发布

我需要考虑如何重现这个错误,这是一个难以重现的简单场景。
这涉及到从一个评估环境中编译一个命名空间。

0 投票
by

评论者:laurentpetit

你好,还有机会将这个问题修复到1.7版本吗?

0 投票
by

评论者:alexmiller

我本来没打算这么做 - 对你有何影响?

0 投票
by

评论者:laurentpetit

影响是,我需要为CCW使用Clojure的修复版本。
虽然目前跟随clojure的主分支并不困难,定期rebase或重新应用补丁,但这仍然是一种浪费时间的方式。

0 投票

评论者:alexmiller

在我们到达RC版本之前,我将与Rich沟通,看是否可以在1.7版本中进行筛选。

0 投票

评论者:alexmiller

与v4补丁相同,只是拥有更多的diff上下文。

0 投票

评论者:laurentpetit

在我看来,补丁字段中提到的文件不是正确的文件。

0 投票

评论者:alexmiller

是哪一个?

0 投票

评论者:laurentpetit

我认为你之前的评论与clj-1620-v5.patch有关,但在描述的末尾有如下一行

补丁:0001-CLJ-1620-avoid-constants-leak-in-static-initalizer-v4.patch

0 投票

评论者:alexmiller

这些补丁在引入的变化方面是等效的;它们只是在diff上下文方面有所不同。

...