Java's Fraught Relationship with Cyclic Object Graphs
Stuart Marks on October 15, 2024A Java program consists of objects that have references to each other. This is called the “object graph.” It’s easy to set up an object graph with cycles. If you do this, some things work, but other things break, sometimes in a surprising fashion. Cyclic object graphs don’t come up very often, but when they do, they often result in difficult and subtle problems. Worse, the JDK doesn’t provide much help here.
Garbage collection works perfectly with cyclic object graphs. Early reference-counted GCs had problems with cycles, but modern tracing collectors handle them perfectly fine. This is a solved problem.
The picture is less rosy in other parts of the system. A cyclic object graph using records or collections often results in a stack overflow or out-of-memory error.
Java serialization claims to support cyclic object graphs. This works only in the simplest of cases. In more complex cases, deserialization will fail in subtle and unpleasant ways. There is a whole family of bug reports in the JDK Bug System that represents these different failure modes.
I’ll show several examples of cyclic object graphs that cause failures, and I’ll explain these failures. I’ll also explain why it’s very difficult for the JDK to do anything effective to prevent them.
Yet there are times when it’s useful for Java applications to represent relationships that have cycles. I’ll describe a set of techniques that can be used to represent cycles and that avoid the problems I’ve described.
Recorded at Devoxx Belgium 2024.