Java Garbage Collection with Assignment of Variables - java

I have been going through the Java tutorials on the Java website and have been left confused with an answer they gave to a question.
The question is as follows: "The following code creates one array and one string object. How many references to those objects exist after the code executes? Is either object eligible for garbage collection?"
String[] students = new String[10];
String studentName = "Peter Smith";
students[0] = studentName;
studentName = null;
Answer: "There is one reference to the students array and that array has one reference to the string Peter Smith. Neither object is eligible for garbage collection."
Why is studentName not eligible for garbage collection? Nothing is pointing to studentName, and it's value is null.

studentName is a variable not an object - you garbage collect only objects.
The only objects in here, as mentioned are the created String[] and "Peter Smith", and both are reachable, and thus not eligable for GC.

studentName is reference to Object not an actual Object,
If you mean Object referred by studentName
String studentName = "Peter Smith";
then it is still being referred by students[0]
students[0] = studentName;

If you look at the documentation on that site it says the following in the summary page:
"The garbage collector automatically cleans up unused objects. An object is unused if the program holds no more references to it. You can explicitly drop a reference by setting the variable holding the reference to null."
Even though the reference to "Peter Smith" is released by studentName when it is set to null, the string array students still has a reference to that object so it's not eligible for garbage collection. The array itself also still has a reference to it. If you put this in a small program and run it and print out students[0] after this code block it will print "Peter Smith"

Related

How to distinguish object and variable in java

I get stuck in this problem in java docs. The second problem's answer said that after the code execute, "Neither object is eligible for garbage collection. The array students is not eligible for garbage collection because it has one reference to the object studentName even though that object has been assigned the value null. The object studentName is not eligible either because students[0] still refers to it."
But I don't think studentName and students are object, they just variables to refer to objects, and they will not be garbage recycled. I think only the String "Peter Parker" is an object in the code below. What's wrong?
...
String[] students = new String[10];
String studentName = "Peter Parker";
students[0] = studentName;
studentName = null;
....
This statement is fundamentally wrong on more levels than confusing objects and variables.
You are right in that it confuses names and objects, to the highest amount ever seen. Not only is “reference to the object studentName” wrong as studentName is not an object, “even though that object has been assigned the value null” is even worse, as objects can not be assigned to null and what is supposed to explain that setting a reference to null does not imply that the referent becomes unreachable, is achieving the opposite.
But that’s not the end, as the entire logic is wrong. Let’s remove the names, to avoid that confusion. Then, the phrase reads as “The array … is not eligible for garbage collection because it has one reference to the object …”. That’s completely wrong. If X has a reference to Y, it does not prevent the garbage collection of X, as only references to X matter.
What may prevent the garbage collection of the array, is the variable students holding a reference to it, but of course, an author who fails to distinguish between variables and objects, is not able to express this relationship.
It’s worth noting, that if students is a local variable, it does not prevent the garbage collection of the array in every case, as explained in Can java finalize an object when it is still in scope? But skipping this in a tutorial may be acceptable for simplification, see also Lie-to-children.
Another issue is that objects created for string literals like "Peter Parker" will stay in memory as long as there’s at least one piece of code in the JVM having a reference to it, as all string literals (and compile-time constants of type string) of the same contents evaluate to the same object.
If you want to go the route of simplified reasoning about garbage collection, the students variable contains a reference to a String[] array instance, which is prevented from garbage collection due to this reference, and the array contains a reference to a String object, which prevents the String instance from garbage collection (in addition to other references which may exist).
Most of the time, you shouldn’t try to guess what the garbage collector could collect, because the very purpose of the garbage collector is to remove the burden of thinking about this from the developer.
Unfortunately, the doc does not clearly distinguish bewtween variables and objects. There are two objects in this snippet: the array new string[10] and the string "Peter Parker". In line 1 the variable students is set to a reference of the array object; in line 2 the variable studentName is set to a reference of the string object; in line 3 the array element 0 is set to a reference to the string object; and finally in line 4 the variable studentName is set to null.
Now the array object cannot be garbage collected because the variable students still holds a reference and the string objects cannot be garbage collected because the array element 0 still has a reference.
If there were a line 5 where the variable students is set to null as well, both objects could be garbage collected because both are no longer reachable (a string literal however is never garbage collected - but this for another reason). It does not matter that the array element 0 still has a reference to the string object in this case because the array object itself is no longer reachable.

Strings - Stack and heap in java

I know that Strings are stored on the heap and the reference to them is stored on the stack. So in the code below one would point to "John" on the heap from the stack and likewise two would point to "Smith" on the heap from the stack.
So what happens when i do one = two?
Does one now point to where two points to because two contains a reference to a point on the heap or does it change the "John" on the heap to "Smith"?
String one;
one = "John";
String two = "Smith"
one = two;
In your example, one now points to the same place as two. The original string on the heap "John" becomes garbage and is subject to garbage collection.
It's not possible to see in this example because String is immutable, but if these were mutable data structures such as an ArrayList, then modifying the object through one would make the same change visible through two, because they point to the same object.
Now one will point to the two .Since all string are immutable then when they are created then they are stored in heap and referenced by variable but when you make or assign new variable to same string then it will not explicitly create new string but just reference to same string which is in heap
from above picture you can easily understand the concept of immutability.
for reference Where does java reference variable stored?

Storing objects in array of objects

Basically i want to add students to a class list. Assuming i have the following code
public class ClassList {
//Constructor methods...
private Student [] studList = new Student [20];
public boolean addStudent (Student newStudent)
{
studList[14] = newStudent;
}
}
Does studList[14] add a reference to newStudent object or copies that object into the studList[14] student object?
As far as i understand newStudent object will get deleted when the method addStudent() is called a second time. So studList[14] will point to null then? What if i want studList[14] to persist throughout the code execution?
Sorry if it is hard to understand, i do not know how to explain my query easier...
There's one fundamental rule in Java that you have to wrap your head around:
The only way you can access an object is via its reference. And the only values that variables can hold are references(*). That's true for local variables, parameters, instance fields and static fields: they all are the same in this respect.
The object itself is never "contained" in a variable.
This directly leads to the answer to your first question:
The reference is copied into the array (as an array can only hold references(*), never objects).
This also mean that "newStudent being deleted" is not actually a big deal: it's just another reference to the same object, and if it goes away nothing much happens.
Now, if all references to a given object are removed (or no longer reachable), then the object itself becomes eligible for garbage collection, but that's not a bad thing, because you could not access it anymore anyway.
(*) ... or primitive values, but we'll ignore those for this dicussion.
The assignment doesn't copy the object. It just adds a reference to the object into the array.
An object gets deleted by the garbage collector after there are no more references to it anywhere. You don't need to worry too much about this process, because it's kind of invisible most of the time; and once there are no references to an object, you couldn't have used it anyway.
Perhaps you want to be able to pass in an int to your method, to tell it which entry in the array to set, instead of always setting entry number 14?
You should have a look at the JLS about types, values and variables:
The values of a reference type are references to objects.
If there is no remaining reference (aside weak ones) to an object it will be garbage-collected out of the heap.
If you call two times: addStudent(new Student());
the first Student object created is qualified for GC since you have no other reference variable "pointing" to the object.

What does ArrayList actually stores - References to objects or actual objects?

Suppose my code goes like this:
ArrayList list = new ArrayList();
Student s = new Student(); // creating object of Student class
myList.add(s); // Here am confused ...
/* myList contains just the reference variable to the Student object, OR
myList contains the actual Student object (memory allocation for name, rollNo etc) ??
*/
In Short when adding objects to ArrayList using add():
ArrayList is a list of "References to objects" or its a list of "actual objects" ???
In Java, you never pass around actual objects. You are always dealing with a reference, which is essentially just an address to a location within memory where your object is stored.
Since you never work with actual objects, ArrayLists contains arrays of references to objects stored somewhere else (a place in memory called the heap).
The objects are stored on the heap, not 'inside' the arraylist. The arraylist stores references to where there objects are found, as you say.
ArrayList stores references to objects. I would advise you to use the generic version of ArrayList.
Your declaration would be:
ArrayList <Student> list = new ArrayList<>();
You would benefit from type checking at compile time.
Also read http://en.m.wikipedia.org/wiki/Object_copy for explanations about object copy concepts and the different strategies adopted by Java and C++.
Objects within the ArrayList themselves are stored on the heap. The ArrayList simply provides references to those objects and the ArrayList instance is also on the heap.
Object references, at the end of the day, are simply addresses to locations within memory where the object is stored. Hence, the ArrayList contains arrays of references to objects stored on the heap (or in memory).
ArrayList stores the references of objects.
The snippet will explain to you
public static void main(String[] args) {
ArrayList<Dog> a=new ArrayList<TEST.Dog>();
Dog d=new Dog("AL");
a.add(d);
d.setName("AFTER");
System.out.println(a);
}
Here we are changing the Dog object independently out side of the list and it is getting reflected to the List, hence a reference is being stored in the list.
I know this is more specific than necessary, but Java stores an Object's reference by value. I would explain it, but there is already a good article here: Java is Pass-by-Value, Dammit!.
Scott Stanchfield also added some extra clarification on stackoverflow/reference-or-value.
Depends on how you see it.
But its always a reference.
Here is an example:
String niceText = "Hallo array List";
ArrayList<String> list = new ArrayList<String>();
list.add(niceText);
System.out.print(niceText + " = " + list.get(0));
// Output: Hallo array List = Hallo array List
niceText = "Goodby list";
System.out.print(niceText + " = " + list.get(0));
// Output: Goodby list = Goodby list
list.get(0) = "Still in here";
System.out.print(niceText + " = " + list.get(0));
// Output: Still in here = Still in here
list.add("New value");
System.out.print(niceText + " = " + list.get(1));
// Output: Still in here = New value
// But there is no referencing object anymore for index 1, it exist only in the list
But you can go much further, by cloning your object or pass it in different ways to other components of your app.
But this has nothing to do with the array list, this is how java handels object instances and there visibility.
ArrayList<Dog> arrayList = new ArrayList<Dog>();
Dog dogReference = new Dog("AL");
arrayList.add(dogReference);
System.out.println(arrayList.get(0)); //Dog#ObjectRef
dogReference.setName("AFTER");
dogReference = new Dog("NEWER");
// This is still referencing old reference though we have re-initialized
System.out.println(arrayList.get(0)); //Dog#ObjectRef
System.out.println(arrayList.get(0).getName()); //AFTER
System.out.println(dogReference.getName()); //NEWER
Initially, I was confused after this example as after re-initializing same variable arrayList still point to the older one. ArrayList uses Object[] to store the references.
I'll bite. This is obviously a question resulting from a larger issue about object references in Java. Perhaps it'll help to ask why you would need to know if your object is being stored by reference or by value.
That's probably the more interesting question to answer as most everything in Java, except primitives and a few others, are stored by reference. To be at a point where you're needing to think about why your thought process needs to know if something is by reference or value is more likely the point where you'll be able to resolve any issues that prompted you to have to ask this question.
Just curious.

Java - why does assigning "null" to variable does not make it available for GC? (In this code snippet)

I was going through the online tutorial provided by oracle. One of the exercises has a question as follows:
The following code creates one array and one string object. How many references to those objects exist after the code executes? Is either object eligible for garbage collection?
...
String[] students = new String[10];
String studentName = "Peter Smith";
students[0] = studentName;
studentName = null;
...
Answer: There is one reference to the students array and that array has one reference to the string Peter Smith. Neither object is eligible for garbage collection.
(http://docs.oracle.com/javase/tutorial/java/javaOO/QandE/objects-answers.html)
Surely the last line means studentName is eligible for GC? Really confused, and I think this means I have not understood the nature of "null" and also object referencing properly, which is why I ask.
Before assigning null to studentName there are two references to "Peter Smith" (studentName and students[0]). After null is assigned to studentName, "Peter Smith" is still referenced by students[0]
What are the objects, actually, that cannot be garbage collected? "Peter Smith" and the String[10] array. Note these are the objects themselves, not the references to the objects! It is enough that just one reference exists to avoid garbage collection.
I use a mental trick which is to be verbose while reading code. It is easy to say "String" (vague) when what you mean is "String object" (the words in the String) or "String reference" (the variable pointing to the words) so this trick avoids this confusion.
Rewriting the pseudocode with my mental trick, labeling everything as object or reference the way I do in my mind:
1 String[] OBJECT student REFERENCE = new String[10] OBJECT;
2 String OBJECT studentName REFERENCE = "Peter Smith" OBJECT;
3 students[0] REFERENCE = studentName REFERENCE;
4 studentName REFERENCE = null;
In line 3 the String[0]_reference was pointed at the "Peter Smith" object. It is now clear that just the studentName reference was set to null but the "Peter Smith" object continues to exist and the array still points to it. Thus the objects aren't ever null, just one reference was nulled.
This page explains the fundamental java concept of references well (and how they are essentially just pointers)
http://javadude.com/articles/passbyvalue.htm
Though not about the question, it is directly relevant. Objects are referenced by pointers (references) in java. Understanding that should help a lot.

Categories

Resources