程序拒绝不断消耗内存

时间:2016-12-02 01:17:05

标签: memory clojure

我正在尝试this challenge,这需要你编写一个不断消耗内存的程序。

我认为这很容易,所以我写了:

(reduce conj [] (range))

这基本上将无限范围内的数字添加到矢量中;理论上永远。

问题是,这会跳到3 / 4GB的内存,然后停止。 CPU仍在努力运行,但它拒绝增长。

我决定从Java答案中窃取一个想法并覆盖finalize以在每次解除分配时创建更多对象:

(defrecord A []
  Object
  (finalize [this] (mapv (fn [_] (A.)) (range 5)))) ; Create 5 more

(mapv (fn [_] (A.)) (range))

但这也会在同一点上停止增长。

这怎么没爆炸?特别是因为我使用严格的map,它应该保留在记忆中的所有内容吗?至于它已经知道",我希望它在某个时刻打印整个列表,所以它需要抓住一切。另外,如果它在某个时候解除分配,那么被覆盖的finalize方法是否应该克服这个问题?

有人能解释一下这里发生了什么吗?我在休息时写了这篇文章,所以我可能会忽略一些东西,但我无法看到。 它在Intellij / Cursive的REPL中进行了测试。

1 个答案:

答案 0 :(得分:2)

您的JVM基本上花费了整个垃圾收集时间。在我的系统上,默认堆大小的限制是~8.7GB,所以根据这给你的不同,你的GC将会更早地保持低于此值:

java -XX:+PrintFlagsFinal -version | grep HeapSize

您可以使用-Xmx JVM选项增加此功能。

您的程序实际上会继续运行并继续向您的向量添加内容。我建议使用选项:XX:+PrintGCDetails启动JVM以查看正在进行的操作。在接近堆限制之后,JVM将在几秒钟内执行Full GC。请注意,if the JVM spends too much time for the GC then it will throw and OOM error

要查看您仍在分配,只需将(when (zero? (rem x 1e5)) (println x))投入:

java -server -Xmx2g -XX:+PrintGCDetails -cp clojure-1.8.0.jar clojure.main -e '(mapv #(cond-> % (zero? (rem % 1e4)) println) (range))'