分享您的想法,请参见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

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

似乎问题在于AOT(重新)编译顶级关键字查找站点,我猜这个补丁可能是防止了__init静态初始化程序的正确生成。

0

评论由:bronsa

我仍然完全不知道Lein编译器在做什么,但我弄清楚了问题。
更新的补丁只在变量已绑定时(在eval中)绑定适当的变量。

0

评论人:alexmiller

现在使用绑定映射的transients是否有意义?

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补丁相同,但只是有更多的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上下文不同。

...