In Java, objects are garbage-collected when they can no longer be reached from any top-level reference. For example, consider this simple code:
Code:
public void foo() {
Parent parent = new Parent();
Child child = new Child();
parent.setChild(child);
child.setParent(parent);
System.out.println("Yey !");
}
When you call foo(), it will create the two objects. When foo() returns, however, both objects will be garbage-collected (*), because there is no way anyone could ever access them from anywhere.
In other words, Java does not use reference-counting for garbage collection; it uses some other algorithm which is nearly magical in its performance speed and accuracy. I honestly have no idea how it works (I'm a n00b), but it does.
Things are not as simple with Hibernate, because Hibernate has a cache that will keep the references to these objects. However, once the objects are evicted from the cache, they'll be gone (assuming that you're not holding a reference to them somewhere).
(*) Actually, they will only be marked for garbage collection; they will only be garbage-collected for real when the JVM decides that it needs more memory.