How Does Java Garbage Collection Work With Circular References

How does Java Garbage Collection work with Circular References?

Java's GC considers objects "garbage" if they aren't reachable through a chain starting at a garbage collection root, so these objects will be collected. Even though objects may point to each other to form a cycle, they're still garbage if they're cut off from the root.

See the section on unreachable objects in Appendix A: The Truth About Garbage Collection in Java Platform Performance: Strategies and Tactics for the gory details.

Circular references in Java and garbage collection

You are thinking too much in technical terms. The garbage collection is defined as any measure capable of reclaiming the storage of unreachable objects.

The Java Language Specification §12.6.1 defines:

A reachable object is any object that can be accessed in any potential continuing computation from any live thread.

A directed reference is a way, how running code may access an object, and, in fact, traversing these references is a typical way how garbage collector implementations detect the reachability of objects, but it must be emphasized that even the existence of, e.g. a local variable, referring to an object is not sufficient to prevent its garbage collection, if no “potential continuing computation” reads it.

This is what happens in practice when the JVM’s optimizer transforms the code, eliminating unused variables and dead code.

The linked section also explicitly states:

Optimizing transformations of a program can be designed that reduce the number of objects that are reachable to be less than those which would naively be considered reachable.

Not getting distracted by these technical details, it is enough to know that only the possibility to access an object is relevant to determine that it is not garbage. So regardless of how objects are interlinked with references, if no live thread can access them, they all are garbage.

How does Java garbage collector deals with circular references when their access path is broken?

There's set of "root objects" which are considered always accessible: e.g., Thread references, static variables, class references. If some object can not be reached via link of references from these root objects, it considered to be available for GC, even if there are some references to that object.

Large circular reference and JVM garbage collector

From a simplistic view, the JVM uses a Tracing Garbage Collection, Mark-and-Sweep. Circular references don't interfere with the correct behavior of such an algorithm because it starts from the "base" level and works it's way through references to find those elements that can be reached from there. Any that cannot be reached are available to be collected/freed.

It's worth noting that the JVM garbage collectors are generally a lot more complex than this, with many optimizations to make things faster. That being said, the general properties of the mark-and-sweep algorithm hold true for it.

Circular References in Java

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.

Garbage collector and circular reference

The .NET garbage collector can absolutely handle circular references. The very high level view of how the garbage collector works is ...

  • Start with locals, statics and GC pinned objects. None of these can be collected
  • Mark every object which can be reached by traversing the children of these objects
  • Collect every object which is not marked.

This allows for circular references to be collected just fine. So long as none of them are reachable from an object known to be uncollectable then the circular reference is essentially irrelevant.

Note: I realize I've left out many fun details in order to keep this answer simple and direct

Garbage collection behavior with isolated cyclic references?

Yes, they are. Basically the GC walks from "known roots" (static variables, local variables from all stack frames in alll threads) to find objects which can't be garbage collected. If there's no way of getting to an object from a root, it's eligible for collection.

EDIT: Tom pointed this out, which I thought was worth lifting into the answer itself:

Technically, static variables are not
roots - they are referenced by classes
which are referenced by class loaders
which are referenced by classes which
are referenced by object which are
referenced by root references.

The difference is likely to be irrelevant most of the time, but it's good to know :)

Java circular references, bad style?

The Java garbage collection is smart enough not to be fooled by circular references. As soon as there are no Strong References to the tree then the entire tree complete with circular references will all be garbage collected.

All you need to do is ensure that there are no references from outside the Tree to anywhere inside the Tree.

If an event was accessing the parent field then that suggests something still had a reference. You will need to clean that up (whether you remove the circular references or not).



Related Topics



Leave a reply



Submit