this question is like my previous one
Given:
3. interface Animal { void makeNoise(); }
4. class Horse implements Animal {
5. Long weight = 1200L;
6. public void makeNoise() { System.out.println("whinny"); }
7. }
8. public class Icelandic extends Horse {
9. public void makeNoise() { System.out.println("vinny"); }
10. public static void main(String[] args) {
11. Icelandic i1 = new Icelandic();
12. Icelandic i2 = new Icelandic();
13. Icelandic i3 = new Icelandic();
14. i3 = i1; i1 = i2; i2 = null; i3 = i1;
15. }
16. }
When line 14 is reached, how many objects are eligible for the garbage collector?
A. 0
B. 1
C. 2
D. 3
E. 4
F. 6
I chose A but the right answer is E, but I don't know Why?
Let's call the three Icelandic objects created in main as A, B and C.
Initialy
i1=A, i2=B and i3=C;
After i3 = i1
i1=A, i2=B and i3=A;
After i1 = i2
i1=B, i2=B and i3=A;
After i2 = null:
i1=B, i2=null and i3=A;
After i3 = i1
i1=B, i2=null and i3=B
In line 14, there are standing references to only B object of type Icelandic. A and C are lost in the running program.
Each Icelandic object that is lost gives garbage collector two objects to collect, ie. the Icelandic object itself and the Long object within every Icelandic, which make the total number of garbage collected objects 4.
Since makeNoise methods are never called, they do not change the outcome.
If you look closely, after all assignments in the end i1 and i3 point to the second object while i2 points to null. This means two Icelandic objects are eligible for GC.
Each Icelandic object contains one Long which makes 4 objects eligible for GC in total. Interestingly if the constant was 12L, the answer would be: 2 due to Long internal constant cache. Also note that "whinny" and "vinny" are from the constant pool and won't be garbage collected.
Once you leave the scope where all i1, i2 and i3 are declared, remaining two objects are eligible for GC as well.
Related
I'm currently studying towards my Java associate certificate and I have the official textbook for study. In the text book is the following example code.
public class Island {
Island i;
public static void main(String[] args) {
Island i2 = new Island();
Island i3 = new Island();
Island i4 = new Island();
i2.i = i3;
i3.i = i4;
i4.i = i2;
I understand here that I have initialised 3 Island objects with reference variables i2, i3 and i4 which each point to their own object. i2 is then redirected to point towards i3 and i3 towards i4 etc. What I don't understand is the need for the "i2.i" dot operator, what exactly is it doing here ? is i2 = i3 not as equally valid ?
If anyone has any good resources on where I can read quite in depth into all of the applications of the dot operator in java that would also be helpful, thanks.
You're using an instance variable of the same type as the class itself (see line Island i). This means, that the class Island holds an attribute i of the same type Island. Every island has therefore a link to another island. Your assignment of i2.i = i3; defines the instance variable of i2 to be i3. In other words: i2 has a link to i3. You can get i3 if you have i2.
If you used the assignment i2 = i3, the value of i2 would be overridden by the reference of i3. This means that i2 is not used anymore and the object behind i3 would also be the same object behind i2 (same object, 2 different variable names).
It's important to be careful with the details here.
You have indeed created three objects, but the objects are distinct from the variables.
Let's simplfy: Consider Island x = new Island();, and Island y; You have two variables, x and y, but only one object. The object doesn't have a name, but it is bound to the variable x, so when you say x, you get that object. And when you say y, you get nothing (y is null).
The dot accesses the object denoted by by the expression that precedes it. So x.i accesses the i member variable of the object that is bound to x, and similarly, y.i is attempting to access a member-variable of no object at all, which causes an exception to be thrown.
So now it is clear that you can say x.i = x; to set the member variable Island.i of the object bound to x to the value that happens to be the same object. Or you could set it to something else, like x.i = new Island(); or x.i = y;.
The dot doesn't have to be preceded by a variable, any expression will do. For example, you could say (new Island()).i = x; to create a new object (which again doesn't have a name; objects never have names) and bind the i member of that object to the object bound to x. Since this object is never bound to any variable, it is immediately eligible for collection.
The point of your code example is that all objects are bound to variables that exist beyond the scope of the i1, i2 and i3 (namely to the member variables of the three objects), and thus they form a reference cycle. An interesting question on the topic of garbage collection is whether the three objects are eligible for collection.
I need your knowledge to explain something very simple that confuses me
As you can see, it's a very beginning practice on Java, and I already face the first confusions.
So the question is, what is true from the A, B, C, D?
A. line 12 prints 4
B. line 13 prints 9
C. line 13 prints 18
D. line 14 prints 18
I know that the answers are C and D but because I'm studying and I try to understand why, could you please explain this to me?
I first thought that the correct ones whas A and B but it comes out that I was wrong.
What is really going on with ob.t = ob2; ob2.t = ob; and whats the role of Test t; in the Class Test?
1 class Test {
2 Test t;
3 static int a;
4 Test(int i) { a = i; }
5 void xchange(Test ob, int i) { ob.a = i * ob.a; }
6 }
7 class Call {
8 public static void main(String args[]) {
9 Test ob = new Test(2); Test ob2 = new Test(3);
10 ob.t = ob2; ob2.t = ob;
11 ob.xchange(ob, 2); ob2.xchange(ob.t, 3);
12 System.out.println(ob.a);
13 System.out.println(ob2.a);
14 System.out.println(ob.t.a);
15 }
16 }
What's the role of Test t; in class Test?
It declares a field in Test of type "reference to Test". Note that variables and fields in Java cannot store objects; they can only store references to objects.
What is really going on with ob.t=ob2; ob2.t=ob;?
It sets the t fields of both Test objects to contain references to each other. So the first object's t field contains a reference to the second object, and vice versa.
It is tempting to say that "it assigns ob's t field to contain a reference to ob2", but strictly speaking this is incorrect, as ob and ob2 are not objects.
Given:
interface Animal { void makeNoise(); }
class Horse implements Animal {
Long weight = 1200L;
public void makeNoise() { System.out.println("whinny"); }
}
public class Icelandic extends Horse {
public void makeNoise() { System.out.println("vinny"); }
public static void main(String[] args) {
Icelandic i1 = new Icelandic();
Icelandic i2 = new Icelandic();
Icelandic i3 = new Icelandic();
i3 = i1; i1 = i2; i2 = null; i3 = i1; //<-- line 14
}
}
When line 14 is reached, how many objects are eligible for the garbage collector?
A. 0
B. 1
C. 2
D. 3
E. 4
F. 6
answer is E. why?
The question, and especially insisting on that particular “correct” answer of 4, doesn’t make much sense, as it draws several assumptions about how a JVM works which are naïve in the best case or simply wrong.
The first thing it does wrong is to assume to know, how many objects are ever created.
The main method creates three instances of Icelandic having an inherited field weight initialized with the value of 1200L. The value 1200L is converted to a Long instance via auto-boxing using the method Long.valueOf which is allowed, but not required to cache frequently requested values. So we can’t predict the number of Long instances created here, it might be one or three, but even two is possible if the caching did not work for all invocations, for whatever reasons.
Then the code is playing around with the local variables holding the three instances and is supposed to hold only one of these instances “after” line 14 but there is no associated code after that line for which this state could have a relevance. The only thing which happens after that line is returning from the main method so after line 14 all local variables are out-of-scope.
Whether there is a point of execution which can be associated with “after line 14” but still being in method main where exactly one instance of Icelandic is in scope depends on whether line debug information have been included in the class file and how the compiler did map byte code instructions to these line numbers.
If the return byte code instruction inserted by the compiler is not associated with line 15, all instances created in the main method might be garbage collected after line 14 but keep in mind that the Long instance might still be referenced from a global cache and hence not be eligible to garbage collection. We simply can’t predict.
There is another aspect of JVM execution: optimization. JVMs are allowed to perform “escape analysis” and elide object creations if they don’t have any impact on the programs semantics. In your program, all objects are unused from a JVMs point of view. So another legal execution scenario is that this main method never creates any object and then there are no object eligible for garbage collection at all.
So each object holds a Long object, so when each Icelandic object is marked for garbage collection, so is the Long value it pointed to. Therefore after:
Icelandic i1 = new Icelandic();
Icelandic i2 = new Icelandic();
Icelandic i3 = new Icelandic();
i3 = i1; i1 = i2; i2 = null; i3 = i1;
the original i3 object is lost, and the original i1 value is lost. i1 and i3 both point to the original i2 keeping it alive (and i2 points to null, keeping nothing alive). This leaves 2 objects getting marked for garbage collection (the original i1 and original i3) as well as the Long value they pointed to, giving you 4 items marked for garbage collection.
I would go with Icelandic 2 objects eligible (object 1 and 3).
Since each Icelandic holds a Long object, it gives us 4.
After Line14, Only original i2 Object is alive, no referemce is point to original i1 and i3, so they are eligible for the garbage collector, and this object has a base type, a long field, lose it to, so 2*2 = 4;
The important stuff is here
Icelandic i1 = new Icelandic();
Icelandic i2 = new Icelandic();
Icelandic i3 = new Icelandic();
i3 = i1; i1 = i2; i2 = null; i3 = i1;
So i3 loses its reference right away so the original object is ready for collection.
i1 and i3 reference i2 so i1s original object is ready for collection.
Then i2 loses its reference so all 3 are null and garbage collected.
I'd personally go with 3. That's a pretty thought provoking question.
This piece of code is from a book. The question is,
how many objects are created
how many objects are eligible for gc when the line // do stuff is reached.
The answers, according to the book, are 5 and 2. Here is the code:
class Dozens {
int[] dz = {1,2,3,4,5,6,7,8,9,10,11,12};
}
public class Eggs{
public static void main(String[] args){
Dozens[] da = new Dozens[3];
da[0] = new Dozens();
Dozens d = new Dozens();
da[1] = d;
d = null;
da[1] = null;
// do stuff
}
}
In answer to the first question, do you also count the int[] dz object as an additional object each time you instantiate Dozens?
Similarly, when you reach // do stuff, in calculating the number of objects eligible for gc, for each Dozens object, do you also count the int[] dz object contained therein?
I did not count the int[] dz objects, and arrived at the answers 5 and 3.
Can someone explain what I might be doing wrong?
Thanks.
I have annotated the code below with comments to highlight where references are created or lost.
When counting allocations, one must include the allocation of the array stored in the field dz. My suspicion is that you counted the assignment of object references to da[0] and da[1] as allocations. Since they are copying a reference, and not creating a new object; they only affect when the objects can become GCable and do not create a new object.
class Dozens {
int[] dz = {1,2,3,4,5,6,7,8,9,10,11,12};
}
public class Eggs{
public static void main(String[] args){
Dozens[] da = new Dozens[3]; // +1 object, the array containing 3 nulls
da[0] = new Dozens(); // +2 objects, Dozens and the array in Dozens.dz
Dozens d = new Dozens(); // +2 objects, Dozens and the array in Dozens.dz
da[1] = d; // +0, d now has two refs to it
d = null; // +0, d now has one ref to it
da[1] = null; // -2, d now has no refs to it so both d and its internal array become available for GC
// do stuff
}
}
Summing the totals up gives, 1+2+2=5 allocations. The -2 at the end concludes that 2 objects have become available for GC
While isolating reference (islands of isolating) a class objects say like the below code
public class Island {
Island i;
public static void main(String [] args) {
Island i2 = new Island();
Island i3 = new Island();
Island i4 = new Island();
i2.i = i3; // i2 refers to i3
i3.i = i4; // i3 refers to i4
i4.i = i2; // i4 refers to i2
i2 = null;
i3 = null;
i4 = null;
// do complicated, memory intensive stuff
}
}
will these objects be garbage collected? How is that possible then what makes the program run if they are garbage collected?
will these objects be garbage collected?
It is dependent on JVM, we can't surely say that object has been GCed.
Further we can only say that they are ready to GCed.
And It will GCed when there is no live ref to Object exist . so you no need to worry about your program JVM will make sure:)
As for the 'what makes the program run if they are garbage collected', guess that you are missing is that only some Island object instances were GCed, and you start running a program on a static method (main), which does not need any object of its class (Island) to be called.
The thread that the JVM created to execute your 'main' method will keep your application alive as long as it remains executing something (or you create another thread).
In Sun JVM they will be collected.
Yes (unless you've got a very old jvm) but only in a major collection. But using recursive classes like this is a bit iffy.