【问题标题】:Why does Leiningen keep its own JVM running?为什么 Leiningen 保持自己的 JVM 运行?
【发布时间】:2026-02-17 19:15:01
【问题描述】:

如果我打电话

lein trampoline repl

Leiningen 启动它自己的 JVM 进程,然后为 repl 启动一个单独的 JVM 并退出。但是调用默认值

lein repl

让两个 JVM 运行。是否有任何理由保持原始 Leiningen JVM 进程运行?为什么不将lein trampoline 行为设为默认并每次都退出?

【问题讨论】:

  • 这会破坏进程树,阻止进程在启动 lein 的父进程发生问题时被清理。
  • lein 启动一个单独的 JVM 的原因非常清楚,这样做有很多理由。为什么要一直保持原始 JVM 运行?
  • @nha 很棒的文章,我去年读过。它解释了trampoline 的工作原理以及何时应该使用它。但它没有回答为什么不总是使用trampoline的问题。

标签: clojure jvm leiningen


【解决方案1】:

这是因为第一个实例设置了环境并将其他所需的参数传递给真正的 jvm 继续运行。

JVM的第一个实例只是一种方便用户的包装器,否则用户必须在每个执行点完成所有传递所需参数的工作,从安全角度来看,这既不友好也不好看。

【讨论】:

  • 为什么不将lein trampoline行为设为默认并每次都退出?
  • 请阅读问题。
  • 嗯,这个问题明确地问,“有什么理由让原始的 Leiningen JVM 进程保持运行吗?”。这似乎回答了这个问题,不是吗?
【解决方案2】:

lein help trampoline 状态:

在不将项目的 JVM 嵌套在 Leiningen 中的情况下运行任务。

计算要在项目进程中运行的 Clojure 代码 给定任务并允许 Leiningen 自己的 JVM 进程在之前退出 运行它而不是启动 Leiningen 的 JVM 的子进程。

使用它来节省内存或解决标准输入问题。

参数:([task-name & args])

所以你可以看到,没有trampoline,第二个 JVM 作为第一个的子进程运行。这就是为什么第一个不能退出的原因——退出会破坏第二个。

另一方面,第一个 JVM 使用trampoline 构造一个 shell 脚本,然后由lein 脚本执行以生成第二个 JVM。所以在这种情况下,第二个 JVM 是 lein 脚本的子代。 How Clojure Babies are Made: Leiningen's Trampoline 详细介绍了这一点。

至于为什么trampoline 不是默认值,我不完全确定。但请记住,并非每个lein 命令都运行项目代码,因此并非每个命令都需要第二个 JVM。

此外,使用trampoline 也可能有一些缺点。例如,看看上面文章中的以下代码行:

# Just don't change :target-path in project.clj, mkay?
TRAMPOLINE_FILE="target/trampolines/$INPUT_CHECKSUM"

对我来说,这意味着如果在project.clj 中设置:target-path 可能会出现问题。

【讨论】:

  • 开始赏金,我希望看到更多关于为什么lein默认不终止其主进程的原因。就个人而言,我相信lein 团队添加了trampoline 以提高其性能,但从未足够信任它以使其成为lein 的默认行为,尽管我没有任何证据可以证明这一点。无论如何,你的答案是最好的,应该得到这个赏金。