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

欢迎!请访问关于页面了解更多关于该机制的信息。

0
编译器

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

因为生成的函数的静态初始化超过64K,这阻止了在某些环境中(例如Rational)CCW的正常工作。

重现步骤

加载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是对的,实际上只需替换thunk-fail.core的全部主体为(:foo {})就足够了。

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

0

评论:bronsa

我对lein compile到底在做什么毫无头绪,但我已经找到了问题。
更新的补丁只在已经绑定的情况下,通过eval绑定适当的变量。

0

评论人:alexmiller

现在使用临时绑定的绑定点图是否值得考虑?

0

评论:bronsa

有道理,已更新补丁以使用临时图

0

评论人:michaelblume

我们能否添加一个测试,在v2补丁存在时测试失败?最好与CLJ-1544补丁独立?我可以尝试自己编写一个,但我对Clojure编译器内部机制不太熟悉。

0

评论:bronsa

我必须考虑如何重现该错误,它不是一个简单的场景。
这涉及到从已评估的上下文中编译一个命名空间。

0

评论人:laurentpetit

你好,还有机会这个问题会纳入1.7版本吗?

0

评论人:alexmiller

没有打算这么做 - 对你有什么影响吗?

0

评论人:laurentpetit

影响在于我需要为CCW使用Clojure的补丁版本。
虽然目前跟踪 Clojure 的主线分支,并定期在它上重新合并或重新应用补丁还不那么困难,但这仍然是一种浪费时间的行为。

0

评论人:alexmiller

在到达 RC 之前,我将与 Rich 确认是否可以在 1.7 中进行筛选。

0

评论人:alexmiller

与 v4 补丁相同,但是有更多的差异上下文。

0

评论人:laurentpetit

我认为,补丁字段中提到的文件不是正确的文件。

0

评论人:alexmiller

哪一个呢?

0

评论人:laurentpetit

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

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

0

评论人:alexmiller

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

...