tags:

views:

124

answers:

4

I have a Swing browser application with a bug that as I add/remove to/from the GUI the memory isn't released for those objects and I'm trying to track down what is holding onto them. Problem is I don't know how to tell when something has actually be fully released from memory.

Is there a way to tell if an object has been released from memory? I'm used to Objective-C where there are several ways to tell.

Thanks

+2  A: 

Edit:

As NoozNooz42 has pointed out, a PhantomReference can do everything a finalizer can, without the problems finalizers present. So, I encourage using PhantomReferences over extending finalize(). I am keeping my original post in tact, since I think Java programmers should at least know that finalize() exists.

Original Post:

Every Java class has a finalize() method that gets run when no other Objects hold a reference to that class. You can extend this method like so:

protected void finalize() throws Throwable {
    try {
        // Do whatever you want
    } finally {
        super.finalize();
    }
}

By doing so, you can figure out if anything holds a reference to the Objects in question. Just make sure you always call super.finalize() if you use this approach.

Reference on finalization:

http://java.sun.com/developer/technicalArticles/javase/finalization/

Justin Ardini
Finalizers should be avoided in Java because they don't give guarantee when the objects are really collected.Also finalize only works when the instance is eligible for collection. Normally problematic objects are held in memory by some other instance so that finalizing doesn't help.See also here: http://my.safaribooksonline.com/0201310058/ch02lev1sec6 (Effective Java by Josh Bloch)
Johannes Wachter
@jwachter: Good point, but your link requires signing in to read.
Justin Ardini
@Justin Ardini: finalization happens **WAY BEFORE** an object is GC'ed. See my answer: the OP is after PhantomReference, not finalizers.
NoozNooz42
At first read it sounds like finalize() is similar to dealloc() in obj-c but now I'm not sure. Is finalize() called by garbage-collection, ie would putting a System.out.println("finalized") in finalize() indicate that the object was being collected?
Shizam
Thanks Justin, that clarified it, not the same.
Shizam
@Nooz: Edited for clarity. The OP was unsure if something was holding a reference to certain Objects. This approach can give confirmation that nothing is.
Justin Ardini
@Justin Ardini: Sorry seems to be one of those links that work only when your refered there by google.
Johannes Wachter
+1  A: 

Try YourKit. It's a Java profiler which can show you your memory usage and what the heck is going on. IIRC, the free trial can integrate with Eclipse and has all of the paid version's features (it just has a time limit).

Brian S
+2  A: 

There are multiple ways of detecting memory leaks. Here the three I'm currently thinking of:

  1. Attaching a Profiler to your application (Netbeans or Eclipse TPTP should be useful here)
  2. Making a heap dump and analyze (with Eclipse Memory Analyzer) what instances of a class are held in memory by which other instances.
  3. Attaching VisualVM to track Garbage Collection status.
Johannes Wachter
@jwachter: but the question didn't mention any memory **leak**. The OP only wants to track when a object is GC'ed.
NoozNooz42
Unfortunately #1 has never worked for my applet, never figured out why. I'll check out VisualVM as well, currently trying YourKit.
Shizam
@NoozNooz42 you're right. But I think you normally only look for when something is collected if there is a memory problem.
Johannes Wachter
+4  A: 

You can't really do it in Java. All the answers mentioning finalizers are really not what you're after.

The best you can do is enqueue a PhantomReference in a ReferenceQueue and poll until you get the reference.

final ReferenceQueue rq = new ReferenceQueue();
final PhantomReference phantom = new PhantomReference( referenceToObjectYouWantToTrack, rq );

You want to read Peter Kofler's answer here (it explains what a PhantomReference is):

http://stackoverflow.com/questions/1599069/have-you-ever-used-phantom-reference-in-any-project

Very interesting read here:

http://www.kdgregory.com/index.php?page=java.refobj

Basically, I'm using a PhantomReference in a project where a very special kind of cache needs to be computed once, when the software is installed. To efficiently compute this (disk-based) cache, a gigantic amount of memory is needed (the more the better). I'm using a PhantomReference to track "nearly exactly" when that gigantic amount of memory is released.

NoozNooz42
Good info and links, looks like Peter suggests using a profiler.
Shizam
Since there's no problem that finalizers can solve that PhantomReferences can't, I updated my answer. I do think that finalizers are "good enough" for what the OP is trying to do, but I realize I shouldn't encourage semi-deprecated techniques.
Justin Ardini
So far the profilers I tried don't have the resolution to show if a single object is released. It looks like this answer (PhantomReferences) may be the best tool but I'm having difficulty finding an example of how to use it to only track released objects. The example at kdgregory is using it to track SQL connections. What exactly am I polling for null values, the referenceQueue or some other tracking list?
Shizam