A thread I spawned is consuming resources, and I’d like to stop it, but I don’t have a reference to it.
(in-ns 'user)
(require 'clojure.pprint)
top-threads
will list threads consuming the most cpu time.
(defn top-threads [& {:keys [order-by max]
:or {order-by :cpuTime
max 10}}]
(let [tmxb (java.lang.management.ManagementFactory/getThreadMXBean)]
(->> (Thread/getAllStackTraces)
(.keySet)
(map (fn [thread] {:id (.getId thread)
:cpuTime (.getThreadCpuTime tmxb (.getId thread))
:userTime (.getThreadUserTime tmxb (.getId thread))
:name (.getName thread)}))
(sort-by order-by >)
(take max)
(clojure.pprint/print-table [:id :cpuTime :name]))))
#'user/top-threads
Run it:
(top-threads :order-by :cpuTime, :max 10)
| :id | :cpuTime | :name | |-----+-------------+----------------------------------------------------| | 90 | 16784392000 | nREPL-session-72e4b7b7-98de-4f27-ac66-dbdbb1fea918 | | 1 | 9403514000 | main | | 44 | 5986613000 | clojure-agent-send-off-pool-1 | | 54 | 3607202000 | clojure.core.async.timers/timeout-daemon | | 66 | 2686516000 | async-thread-macro-5 | | 100 | 2441073000 | pool-3-thread-1 | | 111 | 2131574000 | pool-3-thread-12 | | 114 | 2070166000 | pool-3-thread-15 | | 112 | 1796734000 | pool-3-thread-13 | | 106 | 1741690000 | pool-3-thread-7 |
You can get one with get-thread
:
(defn get-thread [id]
(some->> (.keySet (Thread/getAllStackTraces))
(filter (fn [thread] (= id (.getId thread))))
(first)))
#'user/get-thread
See what the thread is doing:
(clojure.pprint/pprint (.getStackTrace (get-thread 66)))
[[jdk.internal.misc.Unsafe park "Unsafe.java" -2], [java.util.concurrent.locks.LockSupport park "LockSupport.java" 211], [java.util.concurrent.locks.AbstractQueuedSynchronizer acquire "AbstractQueuedSynchronizer.java" 715], [java.util.concurrent.locks.AbstractQueuedSynchronizer acquireSharedInterruptibly "AbstractQueuedSynchronizer.java" 1047], [java.util.concurrent.CountDownLatch await "CountDownLatch.java" 230], [clojure.core$promise$reify__8524 deref "core.clj" 7111], [clojure.core$deref invokeStatic "core.clj" 2324], [clojure.core$deref invoke "core.clj" 2310], [clojure.core.async$fn__7156 invokeStatic "async.clj" 312], [clojure.core.async$fn__7156 doInvoke "async.clj" 301], [clojure.lang.RestFn invoke "RestFn.java" 410], [shadow.cljs.devtools.server.reload_classpath$watch_loop invokeStatic "reload_classpath.clj" 123], [shadow.cljs.devtools.server.reload_classpath$watch_loop invoke "reload_classpath.clj" 119], [shadow.cljs.devtools.server.reload_classpath$start$fn__19096 invoke "reload_classpath.clj" 148], [clojure.core.async$thread_call$fn__7239 invoke "async.clj" 484], [clojure.lang.AFn run "AFn.java" 22], [java.util.concurrent.ThreadPoolExecutor runWorker "ThreadPoolExecutor.java" 1136], [java.util.concurrent.ThreadPoolExecutor$Worker run "ThreadPoolExecutor.java" 635], [java.lang.Thread run "Thread.java" 833]]
And stop it if needed:
(.stop (get-thread 66))