Objects eligible for garbage collection
Asked Answered
S

5

6

This question was taken from Kathy Sierra SCJP 1.6. How many objects are eligible for garbage collections?

According to Kathy Sierra's answer, it is C. That means two objects are eligible for garbage collection. I have given the explanation of the answer. But why is c3 not eligible for garbage collection (GC)?

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 // Do stuff 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

Answer:

  • C is correct. Only one CardBoard object (c1) is eligible, but it has an associated Short wrapper object that is also eligible.
  • A, B, D, E, and F are incorrect based on the above. (Objective 7.4)
Sinistral answered 19/7, 2012 at 15:27 Comment(2)
Strictly speaking c3 can't be eligible for GC, because it is not an object. It is a variable could point to an object.Yours
The correct answer is all of themParadigm
P
6

No object ever existed that c3 points to. The constructor was only called twice, two objects, one each pointed to by c1 and c2. c3 is just a reference, that has never been assigned anything but the null pointer.

The reference c3, that currently points to null, won't go out of scope and be removed from the stack until the closing brace at the end of the main method is crossed.

The object originally assigned to c1 is unreachable because the c1 reference was set to null, but the c2 reference has not been changed, so the object assigned to it is still reachable from this scope via the c2 reference.

Pali answered 19/7, 2012 at 15:36 Comment(3)
It’s an interesting thing that there are so many tutorials and exercises discussing such things and all of them being wrong. The truth is, the JVM has no knowledge of the scope of local variables at all. In the past, this often implied that some references were not cleared despite being out of scope. Today, you might get surprised by the fact that object are collected despite being “in scope”, see “finalize() called on strongly reachable object in Java 8”Paradigm
1) the question is about java 6 2) without knowledge of what '//do stuff' may contain it's impossible to speculate about what optimization conclusions the compiler might make about the future reachability of the c2.Pali
The rules between Java 6 and Java 8 haven’t changed. You can’t even preclude that such things happen in the actual Java 6 implementation, it’s just, that it hasn’t been discussed on SO so far. And if you assume that // do stuff may contain actions relevant to reachability, the correct answer would be that the question is incomplete. It just proves even more, how pointless such question are…Paradigm
V
8

Let's break this down line by line:

CardBoard c1 = new CardBoard();

We now have two objects, the CardBoard c1 points at and the Short c1.story. Neither is available for GC as c1 points at the CardBoard and the story variable of the CardBoard points at the Short...

CardBoard c2 = new CardBoard();

Similar to above, we now have four objects, none of which are available for GC.

CardBoard c3 = c1.go(c2);

We invoke the method go on the CardBoard pointed at by c1, passing the value of c2 which is a reference to a CardBoard Object. We null the parameter, but Java is pass by value meaning that the c2 variable itself is unaffected. We then return the nulled parameter. c3 is null, c1 and c2 are unaffected. We still have 4 objects, none of which can be GC'd.

c1 = null;

We null c1. The CardBoard object which c1 previously pointed at now has nothing pointing to it, and it can be GC'd. Because the story variable inside that CardBoard object is the only thing pointing at the Short, and because that CardBoard object is eligible for GC, the Short also becomes eligible for GC. This gives us 4 objects, 2 of which can be GC'd. The objects eligible for GC are the ones formerly referenced by c1 and c1.story.

Vulnerary answered 19/7, 2012 at 15:42 Comment(0)
P
6

No object ever existed that c3 points to. The constructor was only called twice, two objects, one each pointed to by c1 and c2. c3 is just a reference, that has never been assigned anything but the null pointer.

The reference c3, that currently points to null, won't go out of scope and be removed from the stack until the closing brace at the end of the main method is crossed.

The object originally assigned to c1 is unreachable because the c1 reference was set to null, but the c2 reference has not been changed, so the object assigned to it is still reachable from this scope via the c2 reference.

Pali answered 19/7, 2012 at 15:36 Comment(3)
It’s an interesting thing that there are so many tutorials and exercises discussing such things and all of them being wrong. The truth is, the JVM has no knowledge of the scope of local variables at all. In the past, this often implied that some references were not cleared despite being out of scope. Today, you might get surprised by the fact that object are collected despite being “in scope”, see “finalize() called on strongly reachable object in Java 8”Paradigm
1) the question is about java 6 2) without knowledge of what '//do stuff' may contain it's impossible to speculate about what optimization conclusions the compiler might make about the future reachability of the c2.Pali
The rules between Java 6 and Java 8 haven’t changed. You can’t even preclude that such things happen in the actual Java 6 implementation, it’s just, that it hasn’t been discussed on SO so far. And if you assume that // do stuff may contain actions relevant to reachability, the correct answer would be that the question is incomplete. It just proves even more, how pointless such question are…Paradigm
P
4

c3 is null, so there is clearly no Object there eligible for garbage collection.

Note that only two CardBoard objects are created, the two on these lines:

CardBoard c1 = new CardBoard();
CardBoard c2 = new CardBoard();

and after the reference juggling, only one of them is without references.

Polyester answered 19/7, 2012 at 15:29 Comment(0)
P
1

The formally correct answer is that we don't know. And the reason we don't know is this line:

Short story = 200;

This compiles to the following byte code:

CardBoard();
Code:
   0: aload_0
   1: invokespecial #1                  // Method java/lang/Object."<init>":()V
   4: aload_0
   5: sipush        200
   8: invokestatic  #2                  // Method java/lang/Short.valueOf:(S)Ljava/lang/Short;
  11: putfield      #3                  // Field story:Ljava/lang/Short;
  14: return

Line 8 is the key here, Short.valueOf(), which returns a boxed equivalent of the primitive 200. Let's look at the Javadoc of Short.valueOf():

This method will always cache values in the range -128 to 127, inclusive, and may cache other values outside of this range.

200 is out of the "must cache" range, and thus it falls under "may cache". If it is cached, the value of story won't be eligible for GC when its containing CardBoard instance is. If it isn't cached, story will be unreachable and thus GCed.

To make the question unambiguous (and the proposed answer correct), the code should be amended like this:

Short story = new Short(200);

Update: The 1.6 Javadoc for Short.valueOf() is rather more cryptic than the 1.8 version I quoted, but the same logic applies: there is no way to tell just by looking at the code whether a new or a cached instance of Short will be returned.

Pontine answered 18/3, 2016 at 12:59 Comment(0)
B
-1

If you notice there are only two objects created in the code. c3 is never initialized to an object, it is a null reference. Hence, only one "object" eligible for garbage collection.

Bestow answered 19/7, 2012 at 15:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.