Skip to content

Instantly share code, notes, and snippets.

@stuartsierra
Created March 4, 2011 20:32
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save stuartsierra/855659 to your computer and use it in GitHub Desktop.
Save stuartsierra/855659 to your computer and use it in GitHub Desktop.
Automatic Resource Cleanup with PhantomReferences
(ns resource
"Automatic resource cleanup."
(:import (java.lang.ref ReferenceQueue PhantomReference)))
(def ^:private queue (ReferenceQueue.))
(def ^:private cleanup-fns {})
(defn resource
"Returns a reference to x. At some point after the reference is
garbage-collected, invokes (f x)."
[x f]
(let [r (reify clojure.lang.IDeref (deref [this] x))
p (PhantomReference. r queue)]
(alter-var-root #'cleanup-fns assoc p #(f x))
r))
;; The cleanup thread.
(doto (Thread.
(fn []
(loop [ref (.remove queue)]
((get cleanup-fns ref)) ; TODO: handle exceptions
(alter-var-root #'cleanup-fns dissoc ref)
(recur (.remove queue))))
"resource-cleanup")
(.setDaemon true)
(.start))
(comment
(use 'resource)
;;=> nil
(def r (resource "hello" #(prn "Cleaning up" %)))
;;=> #'user/r
r
;;=> #<resource$resource$reify__11@5abd09e8: "hello">
@r
;;=> "hello"
(System/gc)
;;=> nil
@r
;;=> "hello"
(def r nil)
;;=> #'user/r
r
;;=> nil
(System/gc)
;; "Cleaning up" "hello"
;;=> nil
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment