views:

3230

answers:

9

Given an aggregation of class instances which refer to each other in a complex, circular, fashion: is it possible that the garbage collector may not be able to free these objects?

I vaguely recall this being an issue in the JVM in the past, but I thought this was resolved years ago. yet, some investigation in jhat has revealed a circular reference being the reason for a memory leak that I am now faced with.

Note: I have always been under the impression that the JVM was capable of resolving circular references and freeing such "islands of garbage" from memory. However, I am posing this question just to see if anyone has found any exceptions.

+13  A: 

The garbage collector knows where the root objects are: statics, locals on the stack, etc and if the objects aren't reachable from a root then they will be reclaimed. If they are reachable, then they need to stick around.

Rob Walker
A: 

The garbage collector is a very sophisticated piece of software -- it has been tested in a huge JCK test-suite. It is NOT perfect BUT there is a very good chance that as long as the java compiler(javac) will compile all of your classes and JVM will instantiate it, then you should be good.

Then again, if you are holding references to the root of this object graph, the memory will NOT be freed BUT if you know what you're doing, you should be OK.

anjanb
+3  A: 

No, at least using Sun's official JVM, the garbage collector will be able to detect these cycles and free the memory as soon as there are no longer any references from the outside.

Thilo
+1  A: 

Just to amplify what has already been said:

The application I've been working on for six years recently changed from Java 1.4 to Java 1.6, and we've discovered that we've had to add static references to things that we didn't even realize were garbage collectable before. We didn't need the static reference before because the garbage collector used to suck, and it is just so much better now.

Paul Tomblin
If it couldn't be reached before, how did you know it went away?I wonder if there is some type of link you aren't thinking of that can cause the system to keep it. A thread or a listener.
Bill K
How did you know whether the objects were being garbage collected or not when you must have dropped all references to them? Were they weak references or did you have a link to them through JNI or was it some kind of live object that can be collected even as it is still active?
Brian
The problem was that when we went to reference it, it was gone. I forget the exact details because it was a few months ago, but I think we were calling it through a RMI method.
Paul Tomblin
It turns out that the memory leak can be traced to a class whose instances are stored in a collection, and the class itself has a reference (of type Object) to the the class objects in question - no, I didn't write the code for this one :-)
Ryan Delucchi
+15  A: 

Only a very naive implementation would have a problem with circular references. Wikipedia has a good article on the different GC algorithms. If you really want to learn more, try (Amazon) Garbage Collection: Algorithms for Automatic Dynamic Memory Management . Java has had a good garbage collector since 1.2 and an exceptionally good one in 1.5 and Java 6.

The hard part for improving GC is reducing pauses and overhead, not basic things like circular reference.

David G
+2  A: 

Reference counting GCs are notorious for this issue. Notably, Suns JVM doesn't use a reference counting GC.

If the object can not be reach from the root of the heap (typically, at a minimum, through the classloaders if nothing else0, then the objects will be destroyed as they are not copied during a typical Java GC to the new heap.

Will Hartung
Reference counting is a very good example of a naive implementation.
David G
Actually, it's kind of a clever implementation, it's also a rather simple implementation, and while it has its limitations, it's a viable algorithm, especially in memory constrained environments.
Will Hartung
I've been reading up on MacOs development and apparently ObjectiveC supports both reference count based garbage collection as well as a more sophisticated scheme similar to that of Java.
Ryan Delucchi
+2  A: 

The Java specification says that the garbage collector can garbage collect your object ONLY If it is not reachable from any thread.

Reachable means there is a reference, or chain of references that leads from A to B, and can go via C,D,...Z for all it cares.

The JVM not collecting things has not been a problem for me since 2000, but your mileage may vary.

Tip: Java serialization caches objects to make object mesh transfer efficient. If you have many large, transient objects, and all your memory is getting hogged, reset your serializer to clear it's cache.

Tim Williscroft
+2  A: 

If I remember correctly, then according to the specifications, there are only guarantees about what the JVM can't collect (anything reachable), not what it will collect.

Unless you are working with real-time JVMs, most modern garbage collectors should be able to handle complex reference structures and identify "subgraphs" that can be eliminated safely. The efficiency, latency, and likelihood of doing this improve over time as more research ideas make their way into standard (rather than research) VMs.

Uri
And to emphasize the point, a JVM that assumes infinite heap and never garbage collects is fully compliant (although inefficient ;-)
ddimitrov
+3  A: 

Ryan, judging by your comment to http://stackoverflow.com/questions/176745/circular-references-in-java#176767, you fell into the trap of referencing objects from a class, which was probably loaded by the bootstrap/system classloader. Every class is referenced by the classloader that loaded the class, and can thus be garbage-collected only if the classloader is no longer reachable. The catch is that the bootstrap/system classloader is never garbage collected, therefore, objects reachable from classes loaded by the system classloader cannot be garbage-collected either.

The reasoning for this behavior is explained in JLS. For example, Third Edition 12.7 http://java.sun.com/docs/books/jls/third_edition/html/execution.html#12.7.

Alexander
Actually, we thought that we had it figured out but unfortunately it is now looking like we don't have it. But yes, this is one possibility we should explore.
Ryan Delucchi