【问题标题】:clojure application leaks memory using evalclojure 应用程序使用 eval 泄漏内存
【发布时间】:2015-04-13 15:04:40
【问题描述】:

我的 clojure 应用程序在运行时评估在单独的 .edn 文件中定义的代码,即如果 .edn 文件发生更改,则包含的函数定义将重新加载到原子中,该原子经常用于计算。

如果没有限制,应用程序似乎会在一段时间后填满 JVM 的元空间(无边界)。堆空间使用正常。

我使用“YourKit”分析器来追踪泄漏。似乎大多数分配,包括分析器说“无法从垃圾收集器根中访问”的分配,都来自 eval 调用:

(defn eval-edn [e params_ dynparams_]
  (let [input e
        pairs (seq input)]
    (binding [*ns* (find-ns 'myapp.core)
              moods (:moods input)
              last-moods @state/moods-atom
              effects (:effects input)
              last-effects @state/effects-atom
              params params_
              dynparams dynparams_
              param-stats @state/coreparam-stats]
      (eval input))))

其中paramsdynparams 是动态变量。

.edn 文件如下所示:

{:moods {:happiness 
          (* (:happiness:factor dynparams)
             (* 0.5 (Math/sin (* (/ (- (:weather:temperature params 0) 10) 30) 
                                 Math/PI))))
; ...
}}

具体来说,内存快照将显示数千个 myapp.core$evalN.invoke() 类型的对象,其中 N 是每个新调用都会增加一些索引。

我已经读到应该尽可能避免使用eval,但我不明白如何在没有它的情况下在 JAR 可执行文件中实现在运行时重新加载代码。

如何确保eval 使用的所有内存都被正确清理?

【问题讨论】:

  • 如果不解决内存泄漏本身,而不是将函数定义存储在自定义 EDN 结构中,为什么不将它们作为常规函数定义写在 .clj 文件中,并使用load-file?跨度>
  • 我遇到了同样的问题。我的应用程序设置了一个安全测试器(带有 clojail),它最终评估用户提交的脚本。加载的类在每个 eval 上都会增长,因此元空间会随着时间的推移而填满。

标签: memory-leaks clojure


【解决方案1】:

您不应该使用eval。它不适用于您的用例。请改用tools.reader

https://github.com/clojure/tools.reader

这里有详细讨论:

http://www.learningclojure.com/2013/02/clojures-reader-is-unsafe.html?m=1

【讨论】:

  • 对不起,我正在恢复这个。但事情是这样的,我现在回到另一个项目的代码(我刚刚离开的旧项目,使用 eval 并设置 JVM 选项以控制泄漏);我仍然没有理解你的意思。如何使用tools.reader 进行递归评估?我尝试在字符串中使用#=(如链接示例中所示)来进行评估,但这似乎不尊重动态变量的绑定以调用read-string...
【解决方案2】:

我建议您将“数据”与“执行”(评估)分开。 大概您在 EDN 文件(又名数据)中更改的是关键字和数字。

那么,如果您将定义的操作保留在主代码中而不是数据文件中,并让数据成为数据。如果你的数据还需要指定要做什么操作,你也可以用关键字指明,然后让你的执行代码做相应的动作。

将数据和可执行文件分开在我看来既干净又安全,包括允许您使用专用的 EDN 阅读器来读取和解析输入数据。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-08-30
    • 2016-03-28
    • 2010-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多