Circular References in Java

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.

Are circular references in Java objects bad?

The question you should always ask yourself when doing these things is: would my design, in a real-world-scenario, make sense? And before someone jumps in to correct me, there are cases where design does not map to logic, and there are cases where it does.

When I looked at your code, the first thing which came to mind was how are things stored inside the university software. You need to have information about students, performance evaluation per student and a lot of other inter-connected platforms (email, enrolled courses and so on). This means, that for a given student there are some Performances which have some data. So they belong to the student, so what you did there is good by linking the student to the performance. What I think is wrong is the fact that you may be using that Performance somewhere where you shouldn't and are trying to map it back to the student. Having no bigger picture leaves room for interpretation.

Now, what you could do to decouple the system, if we are to imagine a bigger picture would be to assign an id to a student.

class Student {
private String name;
private String address;
private String city;
private String nationality;
private Data dob;
private long studentId;
}

class Performance {
private long studentId;
private List<Integer> perfData;
}

class PerformanceManager{
private List<Performance> performances;

public List<Performance> getPerformanceForId(long id);
}

class MailItem{
private String to;
private String message;
private long studentId;
}

class MailManager{
private List<MailItem> mails;
private List<MailItem> getMailForId(long id);
}

Of course, the above example is just a simplification, but the idea is that systems which have nothing to do with each other (Performance and Mail) are linked through an id, not through a reference.

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 serialization solve circular reference problems?

Java Serialization uses an IdentityHashMap to map every reference it tries to serialize to an id. The first time it serializes an object it writes its contents and its id. After that, it writes just the id allowing circular references and one copy of an object no matter how many times it is referenced.

The downside is that if you keep the Object stream and don't call reset() it will retain every object you have ever sent resulting in memory usage increasing. Also if you change an object and send it again, the changes won't be apparent as it only sends the reference to the object again.

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.

Solving circular reference

@Transient
private B messageOwner;

This does for the JSON serialization what the transient type modifier does for the normal serialization. If the JSON library supports it.

Of course the messageOwner will be null after deserialisation.



Related Topics



Leave a reply



Submit