Reputation: 1634
1. public class Tahiti {
2. Tahiti t;
3. public static void main(String[] args) {
4. Tahiti t = new Tahiti();
5. Tahiti t2 = t.go(t);
6. t2 = null;
7. // more code here
8. }
9. Tahiti go(Tahiti t) {
10. Tahiti t1 = new Tahiti(); Tahiti t2 = new Tahiti();
11. t1.t = t2; t2.t = t1; t.t = t2;
12. return t1;
13. }
14. }
When line 7 is reached, how many objects are eligible for garbage collection?
as per the answer given for this question, there is no object eligible for GC at line 11; but according to me at least one object, t2, which is set to point null at line 6, should be eligible for garbage collection.
Upvotes: 7
Views: 11283
Reputation: 1052
Heap Stack Diagram is the best way to determine which objects are eligible for garbage collection:
Following is the heap stack diagram of above code:
1000x: TahitiObj: t:2000x
2000x: TahitiObj: 5000x
3000x: TahitiObj: t: 4000x
4000x: TahitiObj: 5000x
5000x: TahitiObj: t: 6000x
6000x: TahitiObj: 3000x
args = null
t = 1000x
t2 = null
Although Go_Stack will be removed from memory after its execution is completed. For completeness I have kept it here.
t = 1000x
t1 = 3000x
t2 = 5000x
By looking at the Main_Stack and HEAP it can be observed that we can reach to all the objects in either direct or indirect way.
So no object is eligible for garbage collection when code execution reaches line number 7 in side main method.
Upvotes: 0
Reputation: 26868
You can just draw a table that maps between lines and the list of access paths pointing to each object immediately after the line, like so:
╔════════════╦═══════════════════════╦════════════════╦═══════════════════╗
║ After Line ║ Pointers to o1 ║ Pointers to o2 ║ Pointers to o3 ║
╠════════════╬═══════════════════════╬════════════════╬═══════════════════╣
║ 3 ║ not allocated ║ not allocated ║ not allocated ║
║ 4 ║ main:t ║ not allocated ║ not allocated ║
║ 9 ║ main:t, go:this, go:t ║ not allocated ║ not allocated ║
║ 10 ║ main:t, go:this, go:t ║ go:t1 ║ go:t2 ║
║ 11 ║ main:t, go:this, go:t ║ go:t1, o3.t ║ go:t2, o2.t, o1.t ║
║ 5 ║ main:t ║ main:t2, o3.t ║ o2.t, o1.t ║
║ 6 ║ main:t ║ o3.t ║ o2.t, o1.t ║
╚════════════╩═══════════════════════╩════════════════╩═══════════════════╝
With o1
, o2
and o3
being the actual objects getting allocated. It can easily be calculated at every point how many objects can be reclaimed; in this case, after line 6 o1
is accessible from a root, o3
is accessible from o1
and o2
accessible from o3
, so no object can be reclaimed.
As a side note, I noticed you wrote "but according to me at least one object, t2, ...". If this is the kind of problems you need to solve, I recommend ditching the habit of naming objects by variables pointing to them; instead give an imaginary id to each object, as I have done above with the o<n>
, and treat variables as pointers to those objects instead of their names. That is because, like pointers and unlike names, an object may have more or less than one variables associated with it, and that list of associated variables can change all the time.
Upvotes: 3
Reputation: 21993
The variable t2 on line 6 is not the only reference to the object. There is a reference from t to the object t2 which was created in the function go which in turn holds a reference to t1 which is the same object that was returned by the function go. So line 6 merely reduces the number of references but there still are live references to the object.
EDIT: Let's try a more elaborate explanation, first I reworked the code a bit to make explaining easier. One statement per line and less confusing variable names + I identified the three relevant objects with the letters A, B and C.
1. public class Tahiti {
2. Tahiti u;
3. public static void main(String[] args) {
4. Tahiti t = new Tahiti(); // object A
5. Tahiti t2 = t.go(t);
6. t2 = null;
7. // more code here
8. }
9. Tahiti go(Tahiti s) {
10. Tahiti s1 = new Tahiti(); // object B
11. Tahiti s2 = new Tahiti(); // object C
12. s1.u = s2;
13. s2.u = s1;
14. s.u = s2;
15. return s1;
16. }
17. }
On line 4: variable t is initiliazed to reference a new object. Let's call that object itself A (it normally has no name in java but for the sake of this explanation it is easier if it does).
On line 5: t is passed to the function go so we go to line 9
On line 9: the parameter s references the object A which was created on line 4
line 10: initializes variable s1 to point to object B
line 11: initializes variable s2 to refer to object C
line 12: s1.u is set to refer to s2 which means object B gets a reference to C
line 13: s2.u is set to refer to s1 so object C get's a reference to B
line 14: s.u is set to refer s2 which means object A get's a reference to C note that C also has a reference to B so at this point there is a chain from A to B
line 15 return object B and return to line 5
line 5: t2 is set to reference object B (B is now referred to two times once directly by t2 and once because t refers to object A which refers to C which refers to B)
line 6: the reference t2 is set to null so B looses one reference but t is still live which point to A refers to C refers to B
Upvotes: 8
Reputation: 3180
At line 5 you're calling the method Tahiti.go()
, so the program jumps from line 5 to 10 and reaches 11 for 6.
Upvotes: 2