tools.nrepl

Thread leak in clojure.tools.nrepl.transport$fn_transport?

Details

  • Type: Defect Defect
  • Status: In Progress In Progress
  • Priority: Major Major
  • Resolution: Unresolved
  • Affects Version/s: 0.2.1, 0.2.2
  • Fix Version/s: 0.2.4
  • Component/s: None
  • Labels:
    None
  • Environment:
    Windows 7 x64, Oracle JDK 1.7.0.11 x64, clojure 1.4.0

Description

When trying out remote eval using your sample in the README, ie

(with-open [conn (repl/connect :port 59258)]
(-> (repl/client conn 1000) ; message receive timeout required
(repl/message {:op "eval" :code "(+ 2 3)"})
repl/response-values))

I'm noticing that hosting process leaking a thread each time the remote eval is called. Jconsole shows a clojure-agent-send-off-pool-xxx thread got spawn as result of the call. The stack appears to be pointing to the "while true" loop inside fn_transport.

java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(SynchronousQueue.java:458)
java.util.concurrent.SynchronousQueue$TransferStack.transfer(SynchronousQueue.java:359)
java.util.concurrent.SynchronousQueue.put(SynchronousQueue.java:878)
clojure.tools.nrepl.transport$fn_transport$fn__3912.invoke(transport.clj:44)
clojure.core$binding_conveyor_fn$fn__3989.invoke(core.clj:1819)
clojure.lang.AFn.call(AFn.java:18)
java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)
java.util.concurrent.FutureTask.run(FutureTask.java:166)
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
java.lang.Thread.run(Thread.java:722)

What do you recommend as way to free the thread? I have server code that calls nrepl on behave of client connections and the number of call can pile up fairly quickly.

Activity

Hide
Chas Emerick added a comment -

Very nice catch. I'd love to have a patch from you; do you have a CA filed? (see http://clojure.org/contributing)

Show
Chas Emerick added a comment - Very nice catch. I'd love to have a patch from you; do you have a CA filed? (see http://clojure.org/contributing)
Hide
David Lao added a comment -

Here is my workaround.

— a/src/main/clojure/clojure/tools/nrepl/transport.clj
+++ b/src/main/clojure/clojure/tools/nrepl/transport.clj
@@ -36,12 +36,12 @@
to the 2 or 3 functions provided."
([read write] (fn-transport read write nil))
([read write close]

  • (let [read-queue (SynchronousQueue.)]
  • (future (try
  • (while true
  • (.put read-queue (read)))
  • (catch Throwable t
  • (.put read-queue t))))
    + (let [read-queue (SynchronousQueue.)
    + transport-thread (future (try
    + (while true
    + (.put read-queue (read)))
    + (catch Throwable t
    + (.put read-queue t))))]
    (FnTransport.
    (let [failure (atom nil)]
    #(if @failure
    @@ -51,7 +51,7 @@
    (do (reset! failure msg) (throw msg))
    msg))))
    write
  • close))))
    + (fn [] (close)(future-cancel transport-thread))))))
Show
David Lao added a comment - Here is my workaround. — a/src/main/clojure/clojure/tools/nrepl/transport.clj +++ b/src/main/clojure/clojure/tools/nrepl/transport.clj @@ -36,12 +36,12 @@ to the 2 or 3 functions provided." ([read write] (fn-transport read write nil)) ([read write close]
  • (let [read-queue (SynchronousQueue.)]
  • (future (try
  • (while true
  • (.put read-queue (read)))
  • (catch Throwable t
  • (.put read-queue t)))) + (let [read-queue (SynchronousQueue.) + transport-thread (future (try + (while true + (.put read-queue (read))) + (catch Throwable t + (.put read-queue t))))] (FnTransport. (let [failure (atom nil)] #(if @failure @@ -51,7 +51,7 @@ (do (reset! failure msg) (throw msg)) msg)))) write
  • close)))) + (fn [] (close)(future-cancel transport-thread))))))

People

Vote (0)
Watch (1)

Dates

  • Created:
    Updated: