3

Taken from SCJP 6 prep book -

Given:

class CardBoard {
    Short story = 200;
    CardBoard go(CardBoard cb) {
        cb = null;
        return cb;
    }
    public static void main(String[] args) {
        CardBoard c1 = new CardBoard();
        CardBoard c2 = new CardBoard();
        CardBoard c3 = c1.go(c2);
        c1 = null;
        // do Stuff
    }
}

When // doStuff is reached, how many objects are eligible for GC?

A. 0

B. 1

C. 2

D. Compilation fails

E. It is not possible to know

F. An exception is thrown at runtime

The correct answer is C - " Only one CardBoard object (c1) is eligible, but it has an associated Short wrapper object that is also eligible."

My question is why is c3 not eligible for collection?

My thoughts are -

c1.go(c2) sets the local reference variable, cb (which is a copy of c2), to null and then returns cb which is assigned to c3. I know that the reference variable for c2 itself cannot be modified in the method, only the object behind it. However it would appear to me that the copy of the reference variable, cb, is set to null and assigned to c3. Why is c3 not set to the returned null in this instance?

sanbhat
  • 17,522
  • 6
  • 48
  • 64
LiamRyan
  • 1,892
  • 4
  • 32
  • 61
  • Hmm. I'm not sure if I like saying "the Short wrapper is also eligibile". My understanding is that, right now the Short object is being referenced by the CardBoard object. The reference is not removed until CardBoard gets GCed right? Can anyone comment on this? Once the CardBoard gets GCed, then the Short will now be eligibile, but at this moment I don't think it is – Cruncher Sep 18 '13 at 14:52
  • The short object is being referenced by the cardboard object, however due to the fact that this is inaccessible to a live thread as the reference which contains the reference is null it is also eligible (isolated reference) – LiamRyan Sep 18 '13 at 14:54

2 Answers2

7

There is no object related to c3. Its value is null, so there's nothing to collect.

Kayaman
  • 72,141
  • 5
  • 83
  • 121
1

That SCJP "correct" answer is bogus. The right answer is either 4 or "It is not possible to know".

If the code is read literally ("// do Stuff" is just a comment), then the object previously reachable from c2 is just as dead and GC eligible as the one previously referred to from c1, and since both of those now-unreachable objects have a c1.story and c2.story objects that will also die with them, a total of 4 objects are eligible for collection.

However, if the "// do Stuff" thing is a placeholder for some unknown code, then that code may or may not use c2, which means that the object referred to by c2 may or may not be dead and eligible for collection when that code is reached. So if we don't know what "// do Stuff" actually is, it's either 2 or 4 that are eligible, and there is no way to tell which.

Gil Tene
  • 798
  • 5
  • 8
  • Actually the C2 reference is never null, the copy of the C2 reference passed into the method c1.go(Cardboard c) is nulled. You can affect objects behind passed reference variables but you cannot alter the object that the original reference variable points to from within a method that it is passed to – LiamRyan Sep 22 '13 at 11:38
  • @LinuxN00b Gil has certainly not tripped on the "Java is pass-by-value" trick; what he said is that, at the point of the `// do stuff` comment, the last usage of `c2` has already been passed over; therefore the object referred to by `c2` is unreachable by definition ("there is no possible future computation which might access it"). – Marko Topolnik Sep 23 '15 at 19:32