views:

189

answers:

5
+2  Q: 

Java references

Is there any way to find all references to an object (in Java)?

I have a cache of objects, and would like to periodically scan it to see if removing the object will cause it to be destroyed.

+2  A: 

There isn't a published way that exposes such an information. Let the language do the garbage collection, it is the job of the JVM vendor to implement it as specified by the language.

Murali
A: 

You could use a reference-counting scheme. Have a class that manages access to these objects, such that you need to call get() on the class (possibly with some argument) to get an instance - this should increment a counter for that instance. When your client code is done with an object, it should return it, decrementing the counter. Then all objects with a count of 0 would be referenced by no one but the container.

Of course, you would need to be very careful that you don't have any code that forgets to decrement the counter before its reference goes out of scope.

danben
I was just typing this out and you beat me :) Just remember if you want that object destroyed you'd have to make the reference to the container = null so it will be picked up by GC
Jordan Messina
+1 for making that explicit
danben
Whomever modded down, care to explain?
danben
This is probably the best solution to the question, but I'm modifying someone else's code and I'm not really sure where the objects would be 'checked back in'. (wasn't me:)
rnd
See my answer for comments about whether reference counting is going to be practical.
Stephen C
+5  A: 

I have a cache of objects

Consider using a WeakHashMap instead of HashMap to get hold of them all.

Here's an extract of the API:

A hashtable-based Map implementation with weak keys. An entry in a WeakHashMap will automatically be removed when its key is no longer in ordinary use. More precisely, the presence of a mapping for a given key will not prevent the key from being discarded by the garbage collector, that is, made finalizable, finalized, and then reclaimed. When a key has been discarded its entry is effectively removed from the map, so this class behaves somewhat differently from other Map implementations.

BalusC
There are actually 3 or 4 reference classes. read through them, one will definitely solve your problem.
Bill K
How does WeakHashMap help him? He wants to know when an object isn't referenced by anything, but (unless he didn't mention it) he doesn't seem to want the objects to be garbage-collected.
danben
In this case its really the value I'm concerned with, and I don't necessarily want it destroyed (other logic needs to apply, if the map is the final reference.
rnd
He wants a cache of objects, a `Map` seemed most logical choice. You can of course homegrow one based on `WeakReference`.
BalusC
@rnd: I didn't see your comment when I was commenting to danben, sorry about that. You may at least find the source of `WeakHashMap` interesting. Check under each the `expungeStaleEntries()` method to get the point wherein the unreferenced references are been removed. Your implementation could do here some additional logic.
BalusC
Thanks here, too.
rnd
There is a reference object to solve exactly the problem of notifying you that your object can be GC'd without letting it be GC'd. Check the OTHER reference classes.
Bill K
(Hint: It's not WeakReference)
Bill K
+6  A: 

You might want to take a look at different reference types Java provides: strong, soft, weak, and phantom.

For cache you would normally wrap a reference into WeakReference or SoftReference and let the object be collected once there are no more strong references left.

Totophil
SoftValueHashMap seems like it will suffice for now, thanks.
rnd
md, you're welcome.
Totophil
For a cache you should favor softReferences as they are meant to keep the referenced object "as long as possible", on contrary weakReferences are meant to let the referenced object be garbage collected as soon as possible. (But as far as I know some VMs have the same implementation for both...)
pgras
+1  A: 

It is not clear what you are really trying to do, so I will answer your question literally.

Is there any way to find all references to an object (in Java)?

There is no way to do this. You can go from a variable or field containing a reference, but Java does not allow you to go in the other direction. It is theoretically possible to do this kind of thing using the Java debugger mechanisms, but it would be too complicated and expensive to be practical.

I have a cache of objects, and would like to periodically scan it to see if removing the object will cause it to be destroyed.

(I assume that you mean removing the object from the cache.) Again, I don't see how you could do this in Java. The SoftReference and WeakReference classes will allow you to tell if an object has been garbage collected, but not if it will be garbage collected. Once again, this kind of thing might theoretically implementable, but it is too complex and expensive to be practical.

However, if your real goal is to implement a cache that does not stop objects being garbage collected, you should be able to do this using WeakHashMap, or by building your own cache that appropriately use WeakReference or SoftReference instances.

EDIT: I suppose that you could also consider an explicit reference counting scheme. However, such a scheme would be difficult to implement properly in Java.

Unlike C++, no destructor gets called in Java when a variable goes out of scope, or on an attribute when its parent object is garbage collected. To implement reference counting, you would need to:

  • add explicit code increment/decrement counts on all assignments to reference counted variables and fields,
  • add try { ... } finally blocks to deal with all possible ways that a reference counted variable can go out of scope, and
  • and add finalize methods to every class that has an attribute of the reference counted type.

It is theoretically possible, but (IMO) it is too difficult to get right in all but the simplest of cases. And (just repeating myself), this is much harder to do in Java than in C++ because Java doesn't have destructors and overloading of assignment operators.

Stephen C
Re: reference counting, I don't think that all of that is relevant WRT the question AS STATED - he says he wants to be able to scan some objects and see which ones aren't being referenced by anything. You don't need explicit increments if you use an accessor, and finalize is totally irrelevant for what he wants to do. Also, I don't agree that its very difficult to do in Java - for a good example, see the way Apache Solr deals with multiple cores.
danben
Although to be fair I do agree that there is a potential pain point in trying to account for the decrements. The resulting code would not be foolproof.
danben
And in the interest of full disclosure I agreed 100% with your post before that, hence the upmod.
danben
@danben - You are assuming that references to reference counted objects won't be held in object instance fields AND that you don't assign them. I don't see how you can glean these assumptions from the question.
Stephen C
@danben - the reason that Apache Solr can get away with the reference counting for dealing with multiple "cores" is that the normal usage patterns are very simple. If an app had to pass ReferenceCounted<T> instances around, put them in fields of shared objects and so on, they'd quickly run into the kind of problems I'm talking about.
Stephen C
Not sure why we are talking about ReferenceCounted<T> - he clearly has a specific use case where he'd like to apply this. Abstractions are nice but not always practical, and I was certainly not recommending it in this case.
danben
@danben - we are talking about ReferenceCounted<T> because you brought up the example of Apache Solr. And that's what Solr uses.
Stephen C
No, that is incorrect. From SolrCore.java (sorry for awful formatting):final void open() { refCount.incrementAndGet(); }and similarly for close().
danben
The point of the above being that, as I stated in my answer originally, it would be the responsibility of the client code to make sure opens and closes are called when they should be, but then there is no need to have some kind of abstraction that knows when you reference something.
danben