1

Let's say I have the following classes as described below:

class A {
    private B b;

    public A {
        b = new B(this);
    }
}

class B {
    private C c;
    private A a;

    public B(A a) {
        this.a = a;
        c = new C(this);
    }

    public removeRefereceToC() {
        c = null;
    }
}

class C {
    private B b;
    public C(B b) {
        this.b = b;
    }
}

If we look at a graph of the references, A references B (and B references A), B references C (and C references B). Now, if we were to call B's method removeReferenceToC(), then B's reference to the object C would be eliminated, but C would still reference B. At this point would C be eligible for garbage collection?

The reason I'm not sure is that because of the direction of the references C can no longer be reached from B which makes me think that C is eligible for garbage collection, however the fact that C still references B is throwing me off.

So if B nulls out its reference to C, will C be eligible for garbage collection?

Edit: This question is being marked as a duplicate. I think the main difference between my question and the previously answered questions can be summed up by this: Previous questions: A -> B <=> C then the ref from A to B gets removed leaving A B <=> C

My question: A <=> B <=> C then the ref from B to C gets removed leaving A <=> B <- C

neonDion
  • 2,278
  • 2
  • 20
  • 39
  • *"however the fact that C still references B is throwing me off. "* Why? What matters is if there are references to an object and not where that object itself refers to. – Tom Jan 11 '17 at 21:21
  • What matters is whether an object can be reached from a GC root: https://www.dynatrace.com/resources/ebooks/javabook/how-garbage-collection-works/ – Blorgbeard Jan 11 '17 at 21:23
  • @Tom The way I'm thinking about this is that there's an arrow pointing from B to C and another arrow pointing from C to B with each arrow indicating a reference. If I null out B's reference to C I'm removing the arrow from B to C, but the arrow from C to B still remains (but it's pointing from C to B). So when the garbage collector does its thing does it think that C is reachable from B still? Or does it see an "arrow" pointing from C to B and realizes that C is not reachable from B? – neonDion Jan 11 '17 at 21:24
  • 1
    References are "directional" - you can't access C from B if you null out `b`. If you can't access it, it's not reachable, by definition. It doesn't matter that there's a C pointing to B, that doesn't help B locate that C. – Blorgbeard Jan 11 '17 at 21:27
  • 1
    Just ask yourself that: is `C` still reachable from `B`? If it isn't why should someone or something assumes that? You "`null`ed" the variable and that is also a common way to "trigger" the removal of an object, as no variable still refers to that object. – Tom Jan 11 '17 at 21:28
  • @Blorgbeard, your explanation of the references being "directional" cleared things up for me. So the graph of references is a directional graph and therefore the GC only cares about arrows pointing out from an object when determining if something should be marked for garbage collection. Arrows in are ignored because they don't indicate reachability. – neonDion Jan 11 '17 at 21:30

1 Answers1

1

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.

Holger
  • 285,553
  • 42
  • 434
  • 765