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

欢迎!请参阅 关于 页面以获取有关如何使用此网站的更多信息。

+1
Clojure
已关闭

我在 J9 JVM 上遇到 Clojure 的问题。

我对 J9 感兴趣,希望 Clojure 不会限制一个人的虚拟机选择。

问题发生在 Windows 和 Linux 上,以及 J9 JVM 的 "11" 和 "15" 版本,以及包括 1.10.1、1.10.2、1.7 和 1.5.1 在内的许多(全部?)Clojure 版本。

这个问题是一个异常或错误,通常源于 clojure.core;频繁的是在 reduce1 中的荒谬 NullPointerException,也被 Leiningen 在 J9 JVM 上抛出。

该问题是不可预测的。但是如果 J9 "始终编译" (-Xcomp),则某些事情肯定会出错,而它似乎在 J9 "始终解释" (-Xint) 时运行良好。由于某种原因,本报告给出的 clojure 命令似乎不尊重 -J 选项,所以我修改了 clojure 脚本来为这次实验传递必要的 JVM 选项。

我使用以下方式安装 clojure

./linux-install-1.10.2.774.sh --prefix ${HOME}/clo

我从 adoptopenjdk.org 获取了 AdoptOpenJDK 版本 11、J9 JVM,用于 Linux。

在首次运行 clojure

${HOME}/clo/bin/clojure

它抛出了 NullPointerException。下面将详细介绍。

尝试各种 JVM 选项后,我发现 -Xint JVM 选项允许 clojure 下载各种东西并显示 REPL 提示。按照 java -X,此选项表示 "仅解释模式执行"。要使用 -Xint,我修改了 clojure 以传递 JVM 选项。(并非所有 clojure 的 Java 调用都认可 -J 选项。)

第一次成功运行后,随后的 clojure 运行通常能够生成 REPL 提示。

然而,-Xcomp JVM 选项使得错误每次都会发生。它的意思是在第一次调用的过程中强制编译方法。

我在尝试使用 Leiningen 2.9.5 的 Windows 版本时第一次遇到了 J9 的问题。我在 Github 上的一个 issues 中记录了部分发现的过程:https://github.com/technomancy/leiningen/issues/2725

NullPointerException 的堆栈跟踪如下

Exception in thread "main" java.lang.NullPointerException
	at clojure.core.protocols$naive_seq_reduce.invokeStatic(protocols.clj:62)
	at clojure.core.protocols$interface_or_naive_reduce.invokeStatic(protocols.clj:72)
     ...
	at clojure.pprint$pprint.invoke(pprint_base.clj:241)
	at clojure.lang.Var.invoke(Var.java:384)
	at clojure.main$report_error$fn__9186$fn__9187.invoke(main.clj:603)
	at clojure.main$report_error$fn__9186.invoke(main.clj:602)
	at clojure.main$report_error.invokeStatic(main.clj:601)
	at clojure.main$main.invokeStatic(main.clj:666)
	at clojure.main$main.doInvoke(main.clj:616)
	at clojure.lang.RestFn.applyTo(RestFn.java:137)
	at clojure.lang.Var.applyTo(Var.java:705)
	at clojure.main.main(main.java:40)

在随后的运行中,我遇到了不同的错误

Syntax error macroexpanding clojure.core/defn- at (clojure/tools/cli.cljc:124:1).
null
 Full report at:
/tmp/clojure-12652663517358293277.edn

并且该文件显示

{:clojure.main/message
 "Syntax error macroexpanding clojure.core/defn- at (clojure/tools/cli.cljc:124:1).\nnull\n",
 :clojure.main/triage
 {:clojure.error/phase :macro-syntax-check,
  :clojure.error/line 124,
  :clojure.error/column 1,
  :clojure.error/source "cli.cljc",
  :clojure.error/symbol clojure.core/defn-,
  :clojure.error/path "clojure/tools/cli.cljc",
  :clojure.error/class java.lang.NullPointerException},
 :clojure.main/trace
 {:via
  [{:type clojure.lang.Compiler$CompilerException,
    :message
    "Syntax error macroexpanding clojure.core/defn- at (clojure/tools/cli.cljc:124:1).",
    :data
    {:clojure.error/phase :macro-syntax-check,
     :clojure.error/line 124,
     :clojure.error/column 1,
     :clojure.error/source "clojure/tools/cli.cljc",
     :clojure.error/symbol clojure.core/defn-},
    :at [clojure.lang.Compiler checkSpecs "Compiler.java" 6976]}
   {:type java.lang.NullPointerException,
    :at [clojure.core$every_QMARK_ invokeStatic "core.clj" 2683]}],
  :trace
  [[clojure.core$every_QMARK_ invokeStatic "core.clj" 2683]
   [clojure.core$every_QMARK_ invoke "core.clj" 2676]
   [clojure.spec.alpha$pcat_STAR_ invokeStatic "alpha.clj" 1388]
   [clojure.spec.alpha$pcat_STAR_ invoke "alpha.clj" 1387]
   [clojure.spec.alpha$deriv invokeStatic "alpha.clj" 1542]
   [clojure.spec.alpha$deriv invoke "alpha.clj" 1528]
   [clojure.spec.alpha$re_conform invokeStatic "alpha.clj" 1669]
   [clojure.spec.alpha$re_conform invoke "alpha.clj" 1660]
   [clojure.spec.alpha$regex_spec_impl$reify__2510
    conform_STAR_
    "alpha.clj"
    1710]
   [clojure.spec.alpha$conform invokeStatic "alpha.clj" 171]
   [clojure.spec.alpha$conform invoke "alpha.clj" 167]
   [clojure.spec.alpha$macroexpand_check invokeStatic "alpha.clj" 708]
   [clojure.spec.alpha$macroexpand_check invoke "alpha.clj" 704]
   [clojure.lang.AFn applyToHelper "AFn.java" 156]
   [clojure.lang.AFn applyTo "AFn.java" 144]
   [clojure.lang.Var applyTo "Var.java" 705]
   [clojure.lang.Compiler checkSpecs "Compiler.java" 6974]
   [clojure.lang.Compiler macroexpand1 "Compiler.java" 6992]
   [clojure.lang.Compiler macroexpand "Compiler.java" 7079]
   [clojure.lang.Compiler eval "Compiler.java" 7165]
   [clojure.lang.Compiler load "Compiler.java" 7640]
   [clojure.lang.RT loadResourceScript "RT.java" 381]
   [clojure.lang.RT loadResourceScript "RT.java" 372]
   [clojure.lang.RT load "RT.java" 459]
   [clojure.lang.RT load "RT.java" 424]
   [clojure.core$load$fn__6857 invoke "core.clj" 6115]
   [clojure.core$load invokeStatic "core.clj" 6114]
   [clojure.core$load doInvoke "core.clj" 6098]
   [clojure.lang.RestFn invoke "RestFn.java" 408]
   [clojure.core$load_one invokeStatic "core.clj" 5897]
   [clojure.core$load_one invoke "core.clj" 5892]
   [clojure.core$load_lib$fn__6797 invoke "core.clj" 5937]
   [clojure.core$load_lib invokeStatic "core.clj" 5936]
   [clojure.core$load_lib doInvoke "core.clj" 5917]
   [clojure.lang.RestFn applyTo "RestFn.java" 142]
   [clojure.core$apply invokeStatic "core.clj" 669]
   [clojure.core$load_libs invokeStatic "core.clj" 5974]
   [clojure.core$load_libs doInvoke "core.clj" 5958]
   [clojure.lang.RestFn applyTo "RestFn.java" 137]
   [clojure.core$apply invokeStatic "core.clj" 669]
   [clojure.core$require invokeStatic "core.clj" 5996]
   [clojure.core$require doInvoke "core.clj" 5996]
   [clojure.lang.RestFn invoke "RestFn.java" 619]
   [clojure.tools.deps.alpha.script.make_classpath2$eval140$loading__6738__auto____141
    invoke
    "make_classpath2.clj"
    9]
   [clojure.tools.deps.alpha.script.make_classpath2$eval140
    invokeStatic
    "make_classpath2.clj"
    9]
   [clojure.tools.deps.alpha.script.make_classpath2$eval140
    invoke
    "make_classpath2.clj"
    9]
   [clojure.lang.Compiler eval "Compiler.java" 7181]
   [clojure.lang.Compiler eval "Compiler.java" 7170]
   [clojure.lang.Compiler load "Compiler.java" 7640]
   [clojure.lang.RT loadResourceScript "RT.java" 381]
   [clojure.lang.RT loadResourceScript "RT.java" 372]
   [clojure.lang.RT load "RT.java" 459]
   [clojure.lang.RT load "RT.java" 424]
   [clojure.core$load$fn__6857 invoke "core.clj" 6115]
   [clojure.core$load invokeStatic "core.clj" 6114]
   [clojure.core$load doInvoke "core.clj" 6098]
   [clojure.lang.RestFn invoke "RestFn.java" 408]
   [clojure.core$load_one invokeStatic "core.clj" 5897]
   [clojure.core$load_one invoke "core.clj" 5892]
   [clojure.core$load_lib$fn__6797 invoke "core.clj" 5937]
   [clojure.core$load_lib invokeStatic "core.clj" 5936]
   [clojure.core$load_lib doInvoke "core.clj" 5917]
   [clojure.lang.RestFn applyTo "RestFn.java" 142]
   [clojure.core$apply invokeStatic "core.clj" 669]
   [clojure.core$load_libs invokeStatic "core.clj" 5974]
   [clojure.core$load_libs doInvoke "core.clj" 5958]
   [clojure.lang.RestFn applyTo "RestFn.java" 137]
   [clojure.core$apply invokeStatic "core.clj" 669]
   [clojure.core$require invokeStatic "core.clj" 5996]
   [clojure.main$main_opt invokeStatic "main.clj" 514]
   [clojure.main$main_opt invoke "main.clj" 510]
   [clojure.main$main invokeStatic "main.clj" 664]
   [clojure.main$main doInvoke "main.clj" 616]
   [clojure.lang.RestFn applyTo "RestFn.java" 137]
   [clojure.lang.Var applyTo "Var.java" 705]
   [clojure.main main "main.java" 40]],
  :phase :macro-syntax-check}}

在再次运行时,我又遇到了不同的错误信息

Exception in thread "main" java.lang.NullPointerException
	at clojure.core$reduce1.invokeStatic(core.clj:944)
	at clojure.core$reduce1.invokeStatic(core.clj:936)
	at clojure.core$merge.invokeStatic(core.clj:3052)
	at clojure.core$Throwable__GT_map$base__7474.invoke(core_print.clj:491)
	at clojure.core$map$fn__5885.invoke(core.clj:2757)
	at clojure.lang.LazySeq.sval(LazySeq.java:42)
	at clojure.lang.LazySeq.seq(LazySeq.java:51)
	at clojure.lang.RT.seq(RT.java:535)
	at clojure.lang.LazilyPersistentVector.create(LazilyPersistentVector.java:44)
	at clojure.core$vec.invokeStatic(core.clj:379)
	at clojure.core$Throwable__GT_map.invokeStatic(core_print.clj:492)
	at clojure.main$report_error.invokeStatic(main.clj:593)
	at clojure.main$main.invokeStatic(main.clj:666)
	at clojure.main$main.doInvoke(main.clj:616)
	at clojure.lang.RestFn.applyTo(RestFn.java:137)
	at clojure.lang.Var.applyTo(Var.java:705)
	at clojure.main.main(main.java:40)

这个问题也可以在 Clojure 1.5.1 中重现

$ java -Xcomp -cp clojure-1.5.1.jar clojure.main
Exception in thread "main" java.lang.ExceptionInInitializerError
	at java.base/java.lang.J9VMInternals.ensureError(J9VMInternals.java:185)
	at java.base/java.lang.J9VMInternals.recordInitializationFailure(J9VMInternals.java:174)
	at java.base/java.lang.Class.forNameImpl(Native Method)
	at java.base/java.lang.Class.forName(Class.java:413)
	at clojure.lang.RT.loadClassForName(RT.java:2098)
	at clojure.lang.RT.load(RT.java:430)
	at clojure.lang.RT.load(RT.java:411)
	at clojure.core$load$fn__5018.invoke(core.clj:5530)
	at clojure.core$load.doInvoke(core.clj:5529)
	at clojure.lang.RestFn.invoke(RestFn.java:408)
	at clojure.core$load_one.invoke(core.clj:5336)
	at clojure.core$load_lib$fn__4967.invoke(core.clj:5375)
	at clojure.core$load_lib.doInvoke(core.clj:5374)
	at clojure.lang.RestFn.applyTo(RestFn.java:142)
	at clojure.core$apply.invoke(core.clj:619)
	at clojure.core$load_libs.doInvoke(core.clj:5413)
	at clojure.lang.RestFn.applyTo(RestFn.java:137)
	at clojure.core$apply.invoke(core.clj:619)
	at clojure.core$require.doInvoke(core.clj:5496)
	at clojure.lang.RestFn.invoke(RestFn.java:408)
	at clojure.lang.Var.invoke(Var.java:415)
	at clojure.main.main(main.java:36)
Caused by: java.lang.NullPointerException
	at clojure.core$reduce1.invoke(core.clj:896)
	at clojure.core$expand_method_impl_cache.invoke(core_deftype.clj:474)
	at clojure.core$_cache_protocol_fn.invoke(core_deftype.clj:542)
	at clojure.core.protocols$fn__5979$G__5974__5992.invoke(protocols.clj:13)
	at clojure.core$reduce.invoke(core.clj:6177)
	at clojure.core$into.invoke(core.clj:6229)
	at clojure.main__init.load(Unknown Source)
	at clojure.main__init.<clinit>(Unknown Source)
已标记为关闭状态,备注为:这是 J9 中的一个 bug,现已修复

3 个回答

+2

被选中
 
最佳答案

如果有人感兴趣的话,J9 的 bug 报告在这里:https://github.com/eclipse/openj9/issues/12191(感谢 Ghadi!)

问题追溯到 j9 中的一次错误更改,并被回滚(见https://github.com/eclipse/openj9/issues/12191#issuecomment-799695842)。

从解决方案中

"修复已提交 #12221 将此修复带到 0.26 版本,该版本将为 Java 8、11 和 16 生成。我们为所有这些 JVM 级别使用相同的 JIT 编译器,因此修复将在 0.26 版本中。

本版本计划于 2021 年 4 月 23 日发布
https://projects.eclipse.org/projects/technology.openj9/releases/0.26.0 "
0

在过去的一周里,Slack 上对 J9 JVM 的问题进行了很多讨论。大家似乎达成的共识是 Clojure 与之不兼容(没有被针对它进行测试)。我刚刚搜索了 J9,发现有很多关于 J9 JVM 的浏览渠道报告说出现了相当随机的行为。

在火灾发生时,处于有两个出口的地方是非常好的。拥有两个主流的认证 JVM 就像这样。你不需要每年都尝试逃生路线。但是,如果尝试逃生路线,发现它被锁了,哎呀。特别是当其他人都可以顺畅地使用逃生路线时,它似乎只有对你来说是锁着的,据推测是因为你大脑中有特殊的植入物。

我将此事提出,以提供详细信息以启动 Jira 问题。这是我们确立有利于发现替代方案或清晰的上游缺陷报告的条件的方式。

在 Clojure 的版本(远至 1.5.1)中,`reduce1` 被提及为 J9 版本 11 & 15 中的直接原因,这使得我希望故障可以缩小范围,或者找到替代方案,或者将问题吸引到 J9 缺陷修复人员的注意。
我怀疑 `reduce1` 没有什么特别的地方,更有可能的是,它显示出来是因为它是 JVM 中最早运行的 lazy seq 代码之一。不会令我惊奇的是,如果 npe 与本地清理的字节码有关,这是 Clojure 编译器输出的,但从 Java > JVM 的角度来看是比较不寻常的,并且涉及到大多数遍历 lazy seq 的函数。
这是一个有潜力的理论。还有一个堆栈跟踪,问题出现在`some`。
我已经在上面提到了这个问题,但不确定人们具体会收到什么样的通知 - https://github.com/eclipse/openj9/issues/12191
他们发现了一个导致这个问题的具体问题: https://github.com/eclipse/openj9/issues/12191#issuecomment-797840254

Alex的初步猜测是对的 :-) - 并非问题出在Clojure本身。

还有一些更加微妙的问题,比如散列函数之间的一点差异 - 参考本文末尾: https://www.royvanrijn.com/blog/2018/05/openj9-jvm-shootout/

这些微妙的问题将难以从每个依赖项中根除。我的观点是,关注OpenJDK-16的一些重要部分可能会带来更高的投资回报率 - 至少根据我们的东西,这也显示出一些令人印象深刻的性能优势。
Clojure对特定的散列值不提供任何保证,因此我认为散列值的差异本身不是一个问题(只要一般性保证保持不变——相等的东西应该有相同的散列码)。
by
我同意Clojure本身运行良好的观点(就技术巅峰系统中的每个项目而言也是如此);这正是我上面提到的一个观点。然而,我个人会担心JVM生态系统中的其他所有可能的依赖。

主要是我对您首次尝试就成功感到印象深刻。
0
by
by
他们在openj9-0.26.0中修复了它!感谢Clojure Squad对于缩小问题并追随着Eclipse编译器编写者的工作!
...