-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* GC-based cleanup of resources are now possible. * 3.0 * snap
- Loading branch information
Showing
4 changed files
with
134 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package tech.resource; | ||
|
||
import java.lang.ref.*; | ||
import java.util.concurrent.Callable; | ||
|
||
|
||
|
||
public class GCReference extends WeakReference<Object> | ||
{ | ||
Callable disposer; | ||
public GCReference( Object item, ReferenceQueue<Object> q, Callable _disposer) | ||
{ | ||
super(item, q); | ||
disposer = _disposer; | ||
} | ||
public void dispose() throws Exception | ||
{ | ||
synchronized(this) { | ||
if(disposer != null) { | ||
disposer.call(); | ||
disposer = null; | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
(defproject techascent/tech.resource "2.1-SNAPSHOT" | ||
(defproject techascent/tech.resource "3.1-SNAPSHOT" | ||
:description "Exception-safe threadsafe resource management" | ||
:url "http://github.com/tech-ascent/tech.resource" | ||
:license {:name "Eclipse Public License" | ||
:url "http://www.eclipse.org/legal/epl-v10.html"} | ||
:dependencies [[org.clojure/clojure "1.9.0"]]) | ||
:dependencies [[org.clojure/clojure "1.9.0"]] | ||
:java-source-paths ["java"]) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
(ns tech.gc-resource | ||
(:require [tech.resource :as resource]) | ||
(:import [java.lang.ref ReferenceQueue] | ||
[java.lang Thread] | ||
[tech.resource GCReference])) | ||
|
||
(set! *warn-on-reflection* true) | ||
|
||
|
||
(def ^:dynamic *reference-queue* (ReferenceQueue.)) | ||
|
||
|
||
(defn watch-reference-queue | ||
[run-atom ^ReferenceQueue reference-queue] | ||
(try | ||
(println :tech.gc-resource "Reference thread starting") | ||
(loop [continue? @run-atom] | ||
(when continue? | ||
(let [next-ref (.remove reference-queue 100)] | ||
(when next-ref | ||
(if-not (satisfies? resource/PResource next-ref) | ||
(println :tech.gc-resource "ReferenceItem in queue is not releasable!!") | ||
(try | ||
(resource/release-resource next-ref) | ||
(catch Throwable e | ||
(println :tech.gc-resource "Failed to release resource:" next-ref e))))) | ||
(recur @run-atom)))) | ||
(catch Throwable e | ||
(println :tech.gc-resource "!!Error in reference queue!!:" e))) | ||
(println :tech.gc-resource "Reference queue exiting")) | ||
|
||
|
||
(defn start-reference-thread | ||
[] | ||
(let [run-atom (atom true) | ||
thread (Thread. #(watch-reference-queue run-atom *reference-queue*))] | ||
(.start thread) | ||
{:thread thread | ||
:close-fn #(do | ||
(reset! run-atom false) | ||
(.join thread))})) | ||
|
||
|
||
(def ^:dynamic *reference-thread* (start-reference-thread)) | ||
|
||
|
||
(extend-protocol resource/PResource | ||
GCReference | ||
(release-resource [^GCReference item] | ||
(.dispose item))) | ||
|
||
|
||
|
||
(defn track-gc-only | ||
"Track this item using weak references. Note that the dispose-fn must absolutely | ||
*not* reference the item else nothing will ever get released." | ||
[item dispose-fn] | ||
(GCReference. item ^ReferenceQueue *reference-queue* dispose-fn) | ||
item) | ||
|
||
|
||
(defn track | ||
"Track an item via both the gc system *and* the stack based system. | ||
Dispose will be first-one-wins." | ||
[item dispose-fn] | ||
(let [gc-ref (GCReference. item *reference-queue* dispose-fn)] | ||
(resource/track gc-ref) | ||
item)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
(ns tech.gc_resource_test | ||
(:require [tech.gc-resource :as gc-resource] | ||
[tech.resource :as resource] | ||
[clojure.test :refer :all])) | ||
|
||
|
||
(deftest gc-resources | ||
(testing "System.gc cleans up the things" | ||
(let [counter (atom 0)] | ||
(let [create-fn (fn [] | ||
(swap! counter inc) | ||
(gc-resource/track (Object.) #(do | ||
(swap! counter dec))))] | ||
(->> (repeatedly 100 #(create-fn)) | ||
dorun) | ||
(is (= 100 @counter)) | ||
(System/gc) | ||
(Thread/sleep 100) | ||
(is (= 0 @counter))) | ||
(System/gc) | ||
(is (= 0 @counter)))) | ||
(testing "resource context and system.gc work together" | ||
(let [counter (atom 0)] | ||
(resource/with-resource-context | ||
(let [create-fn (fn [] | ||
(swap! counter inc) | ||
(gc-resource/track (Object.) #(swap! counter dec))) | ||
objects (vec (repeatedly 100 #(create-fn)))] | ||
(is (= 100 @counter)) | ||
(System/gc) | ||
(Thread/sleep 100) | ||
(is (= 100 @counter)) | ||
;;The compiler is careful to null out things that are no longer in use. | ||
objects)) | ||
(is (= 0 @counter)) | ||
(System/gc) | ||
(Thread/sleep 100) | ||
(is (= 0 @counter))))) |