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

欢迎!请参阅关于页面获取更多有关此工作方式的信息。

0投票
编译器

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

由于生成的函数的静态初始化超过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

我对lein compile做了什么完全一无所知,但我已经找到了问题所在。
更新后的补丁仅在实际绑定变量时(在eval中)绑定适当的变量。

0投票

评论者:alexmiller

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

0投票

评论者:bronsa

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

0投票

评论者:michaelblume

我们能否添加一个测试来检测v2补丁是否存在问题?最好是与CLJ-1544补丁无关的独立测试。我自己尝试写一个,但我对Clojure编译器内部不是很熟悉。

0投票

评论者:bronsa

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

0投票

评论者:laurentpetit

大家好,这个issue是否有可能纳入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-避免静态初始化中的常量泄漏-v4.patch

0投票

评论者:alexmiller

这些修补程序在引入的更改方面是等效的;它们只是在差异上下文的数量上有所不同。

...