Clojure中无限循环中的内存泄漏

时间:2016-01-01 20:49:39

标签: heroku memory-leaks clojure

我有以下功能:

(defn- clock-process [every f]
  (while true
  (f)
  (Thread/sleep every)))

我正在将它旋转到自己的线程中,以避免阻塞主线程:

(future
  (clock-process 3600000 ;; fire every hour
    #(intensive-fn ...)))

在Heroku dyno上,每小时间隔的总内存使用量大幅增长:

enter image description here

内存中断的地方是应用程序重新启动的地方。

有谁能帮我理解发生了什么?

1 个答案:

答案 0 :(得分:1)

我不知道足以帮助您理解为什么会发生这种情况,但我可以建议一些方法来缓解这个问题。

tl; dr:降低堆大小可能是最好的选择。

首先,设置Memory logging agent。这会定期将一些消息打印到日志中,如:

source=web.1 measure.mem.jvm.heap.used=33M measure.mem.jvm.heap.committed=376M measure.mem.jvm.heap.max=376M
source=web.1 measure.mem.jvm.nonheap.used=19M measure.mem.jvm.nonheap.committed=23M measure.mem.jvm.nonheap.max=219M
source=web.1 measure.threads.jvm.total=21 measure.threads.jvm.daemon=11 measure.threads.jvm.nondaemon=1 measure.threads.jvm.internal=9

由此,您将能够确定增长发生的位置(即堆或非堆)。

如果您发现增长都是堆,则应尝试设置最大堆大小(即-Xmx)。低于默认值。像-Xmx300m这样的东西应该足够了,但你可能会降低。您还可以生成一些堆转储,并使用Eclipse MAT之类的工具对其进行分析,如果您想要查明来源。

如果您发现增长是在非堆中,那么请使用troubleshooting guide中描述的其他一些步骤来确定它是否是Metaspace或其他内容。如果它不在Metaspace中,那么您可能会有本机内存泄漏,这可能是由于保留文件句柄或缓冲区而导致的。

您是否尝试过在本地重现此问题?如果你这样做,使用像VisualVM和jmap这样的工具更容易深入挖掘。

最后,您可以打开support ticket with Heroku。他们可以查看smaps之类的内容来帮助解决非堆/本机内存泄漏问题。