How can I test (what tools do I use) if my reference graph is correct and if objects are released at appropriate times (and there are no memory leaks)?
In my case I’m using Java, but answers related to another languages are welcome too…
3
Weak references and the Reference class in general can be checked for its reachability by calling isEnqueued()
. This is essentially asking if it is scheduled to be removed by the garbage collector (and hence the object which WeakReference
points to is about to be nullified by the way WeakReference
works).
However, this offers no guarantee that you’ll be able to “catch” an object before it gets removed by the garbage collector. It may be that one moment its reference is being utilized in another class and the next, that same instance has already gone out of scope and has since been removed by the garbage collector.
An alternative approach could be to keep a list of (normal) references to instances. When you wish to see if it is the only reference left, create a WeakReference
of that instance, and then set the normal reference to null. If it is the only reference left, then isEnqueued()
of the WeakReference
of that instance should immediately return true. Technically, the garbage collector could run at any moment, even after the very line where you set the normal instance to null, however it is extremely improbable. You could probably force the garbage collector to run prior if you want to further reduce this chance.
The only disadvantage of this approach is, yeah, you’re potentially holding a bunch of references to objects that would otherwise be deleted. Though you could remedy this by holding on to a list of SoftReference
references to those instances, which is essentially like a WeakReference
except that it won’t let the reference go unless you absolutely needed more memory.
In this way, you can be sure that this class won’t interfere with cleanup, and yet you can still keep track of if an instance would be deleted or not. After you handle the event, however, you should do the responsible thing and remove your SoftReference
afterwards thereby allowing your instance to be set free to roam the Elysian Fields.
I hope that helps. Let me know if that answered your question.
3
If your goal is just to keep a log of when objects are no longer being used, I’d look into ReferenceQueue, which should be more efficient than doing your own constant loops of Reference.isEnqueued()
checks.
The choice about what kind of reference to use is trickier, and depends on when you want to be alerted and what kind of information about the object you need available. In particular, I’d also look at PhantomReference as an alternative to WeakReference.
It’s a bit roundabout, but you add items to the ReferenceQueue
by passing the queue into their constructor, e.g.:
Foo targetFoo; /* stuff */
ReferenceQueue<Object> refq = new ReferenceQueue<Object>();
WeakReference<Foo> pr = new WeakReference(targetFoo, refq);
In a separate thread, you can loop and wait for when changes occur:
Reference<Object> ref = fooQueue.remove(); // Blocks, poll() is also possible
In this way, you can have code that monitors when certain objects are no longer strongly-reachable.
P.S.: Since the original Foo
may be effectively gone, one way to maintain information about it is to make your own subclass of Reference
, one that stores information about the Foo
so that you can access it later.
Foo targetFoo; /* stuff */
ReferenceQueue<Object> refq = new ReferenceQueue<Object>();
// Use custom subclass of WeakReference
MyReference<Foo> ref = new MyReference(targetFoo, refq);
ref.setStuff("hello");
// Later, in another thread, etc.
MyReference<Object> ref = (MyReference<Object>) fooQueue.remove();
String msg = ref.getStuff();
3