Memory leaks clojure应用程序使用eval泄漏内存

Memory leaks clojure应用程序使用eval泄漏内存,memory-leaks,clojure,Memory Leaks,Clojure,我的clojure应用程序在运行时对单独的.edn文件中定义的代码进行求值,也就是说,如果.edn文件发生更改,所包含的函数定义将重新加载到atom中,该atom将不断用于计算 如果不受限制,应用程序似乎会在一段时间后填满JVM的元空间(无限制)。堆空间使用是正常的 我用“YourKit”探查器追踪泄漏。似乎大多数分配,包括探查器说“无法从垃圾收集器根访问”的分配,都来自eval调用: (defn eval-edn [e params_ dynparams_] (let [input e

我的clojure应用程序在运行时对单独的
.edn
文件中定义的代码进行求值,也就是说,如果
.edn
文件发生更改,所包含的函数定义将重新加载到atom中,该atom将不断用于计算

如果不受限制,应用程序似乎会在一段时间后填满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))))
其中,
params
dynparms
是动态变量

.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
使用的所有内存都已正确清理

您不应该使用
eval
。它不适用于您的用例。使用
工具。改为使用reader

详细讨论如下:


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

那么,如果您保留主代码中定义的操作而不是数据文件中定义的操作,并让数据成为数据,该怎么办呢。如果您的数据还需要指定要执行的操作,您也可以使用关键字来指示,然后让您的执行代码相应地执行


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

无需解决内存泄漏问题,而无需将函数定义存储在自定义EDN结构中,为什么不将它们作为常规函数定义写入.clj文件并使用呢?我也遇到了同样的问题。我的应用程序设置了一个安全测试程序(使用clojail),最终评估用户提交的脚本。加载的类在每次求值时都会增长,因此元空间会随着时间的推移而填满。很抱歉,我正在恢复此操作。但事情是这样的,我现在回到另一个项目的代码(我刚刚离开的旧项目使用eval并设置JVM选项来控制泄漏);我还不明白你的意思。如何使用
tools.reader
进行递归求值?我尝试在字符串中使用
#=
(如链接示例中所示)进行求值,但这似乎不尊重调用
读取字符串的动态变量绑定。。。