吐出来的内存不足

时间:2013-08-07 12:44:15

标签: clojure

我不明白为什么我的代码会引发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"
        )
    )

)

谢谢!

2 个答案:

答案 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