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

时间:2015-04-13 15:04:41

标签: memory-leaks clojure

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

如果它没有限制,应用程序似乎会在一段时间后填满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使用的所有内存都已正确清理?

2 个答案:

答案 0 :(得分:0)

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

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

详细讨论:

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

答案 1 :(得分:0)

我建议您保留"数据"与"执行"分开(EVAL)。 据推测,您在EDN文件(即数据)中更改的是关键字和数字。

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

保持数据和可执行文件分离对我来说既清晰又安全,包括允许您使用专用的EDN阅读器来读取和解析输入数据。