程序拒绝不断消耗内存

我正在尝试
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))

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

这怎么没爆炸?特别是因为我使用了严格的地图,它应该保留在内存中的一切不应该吗?就它“知道”而言,我希望它能在某些时候打印整个列表,所以它需要保留所有内容.另外,如果它在某些时候解除分配,那么被覆盖的终结方法是否应该克服这一点?

谁能解释一下这里发生了什么?我在休息时写了这篇文章,所以我可能会忽略一些东西,但我看不清楚是什么.
它在Intellij / Cursive的REPL中进行了测试.

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

java -XX:+PrintFlagsFinal -version | grep HeapSize

您可以使用-Xmx JVM选项增加此值.

您的程序实际上将继续运行并继续向您的向量添加内容.我建议使用以下选项启动JVM:XX:PrintGCDetails以查看发生了什么.在接近堆限制之后,JVM将在几秒钟内执行Full GC.注意,那个if the JVM spends too much time for the GC then it will throw and OOM error.

要看到你还在分配,只需抛出(当(零?(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))'    
点赞