我不明白为什么我的代码会引发Out of memory异常。
我有一个代理调用一个函数,该函数在“test.log”文件中附加一行。内存不足是PersistentHashMap $ BitmapIndexedNode.assoc(PersistentHashMap.java:624)
。
(use 'clojure.java.io)
(def the-agent(agent nil))
(defn process [_o content]
(spit "test.log" content :append true)
)
(defn write-all []
(doseq
[x (range 1 5000000)]
(send-off
the-agent
process
"Line to be appended\n"
)
)
)
谢谢!
答案 0 :(得分:4)
如果有许多代理同时运行阻塞(或长途)任务,您可能会遇到Clojure默认行为的问题。默认情况下,send-off
使用无界并行,在这种情况下往往会失败。幸运地在 Clojure 1.5 plus 中,您可以设置send-off使用的执行策略来限制并行执行的程度
(use 'clojure.java.io)
(def the-agent (agent nil))
(defn process [_o content]
(spit "test.log" content :append true))
(set-agent-send-executor!
(java.util.concurrent.Executors/newFixedThreadPool 20))
(defn write-all []
(doseq
[x (range 1 5000000)]
(send-off
the-agent
process
"Line to be appended\n")))
然后在没有内存耗尽的情况下完成:
hello.core> (write-all)
nil
hello.core>
这是影响所有代理的全局更改在大多数情况下,最好专门为此任务创建一个线程池,并使用send-via
来使用该特定池:
(def output-thread-pool (java.util.concurrent.Executors/newFixedThreadPool 20))
(defn write-all []
(doseq
[x (range 1 5000000)]
(send-via output-thread-pool
the-agent
process
"Line to be appended\n")))
这允许您为每个任务选择所需的并行度。只需记住在完成它们后关闭线程池。
答案 1 :(得分:2)
在单个吐出的I / O上阻止调度的发送。这些调度的创建速度比完成它们的速度要快得多。
(defn write-all []
(doseq [x (range 1 5000000)]
(send-off the-agent process "foo")
(when (zero? (mod x 100000))
(println (. the-agent clojure.lang.Agent/getQueueCount)))))
user=> (write-all)
99577
199161
298644
398145
497576
596548
Exception in thread "nREPL-worker-0" java.lang.OutOfMemoryError: Java heap space