SCJP Question to Figure When Object Gets Garbage Collected? - java

I can't figure out an SCJP questions even after getting the right answer:
From the following code(source: http://scjptest.com), we need to determine when is object referenced as myInt be eligible for garbage collection:
01.public void doStuff() {
02. Integer arr[] = new Integer[5];
03. for (int i = 0; i < arr.length; i++) {
04. Integer myInt = new Integer(i);
05. arr[i] = myInt;
06. }
07. System.out.println("end");
08.}
The answer states that it is eligible for GC on line 6. But I think the object is simply not eligable for GC until after line 7. Because, the object being referenced as myInt is also referred to as arr[i] as well. So, don't you think, since, after myInt going out of scope, arr[] still has a reference to it till line 8?

The reasoning for the SCJP answer is that at line 6 there are no remaining statements in the scope of arr that refer to it. Under normal circumstances, this would make the array and its elements eligible for garbage collection.
(The Java Language Spec (12.6.1) says this:
"A reachable object is any object that can be accessed in any potential continuing computation from any live thread. Optimizing transformations of a program can be designed that reduce the number of objects that are reachable to be less than those which would naively be considered reachable. For example, a compiler or code generator may choose to set a variable or parameter that will no longer be used to null to cause the storage for such an object to be potentially reclaimable sooner. "
As you can see, the real definition of reachability is not actually based on scoping.)
There is another twist to this question ...
If they had assigned i to myInt, autoboxing will use Integer.valueOf(i), and that method would have recorded the Integer object in a static cache. This cache would have caused the object to remain reachable ...
However, the Integer instance is created using new, so caching does not occur. And the object is unreachable at line 6.

arr[i] = myInt creates a copy of the reference to new Integer(i), not a reference to myInt; therefore, myInt isn't strictly required to exist after that assignment.

Contrary to popular belief, Java object variables contain references to objects and not the object itself. When one object variable is assigned to another, the reference gets copied instead of the object. AFAIK GC is for an object and not a reference. We all know the GC claims an object when no reference to it exists.
In my opinion, the object referenced by myInt wont be available for collection until the function doStuff returns (line 8). object referenced by myInt gets stored in arr which is in scope till the function returns.

arr and myInt are last referenced on line 5. Since it's not referenced in line 7 I can see why line 6 is the stated answer.

From JLS §12.6.1:
A reachable object is any object that can be accessed in any potential continuing computation from any live thread. Optimizing transformations of a program can be designed that reduce the number of objects that are reachable to be less than those which would naively be considered reachable. For example, a compiler or code generator may choose to set a variable or parameter that will no longer be used to null to cause the storage for such an object to be potentially reclaimable sooner.
So, under this definition array referenced by arr can be considered unreachable after line 6, therfore its elements are unreachable as well.

Related

How to delete an (effectively) final array in Java

I want to delete remove the reference to a large array by nulling the reference after I used it. This gives me a compiler error however, since the parallel assignment to the array requires the array to be (effectivly) final (at least that is what I think the problem is...). How can I allow the garbage collection to remove the array?
double[][] arr = new double[n][n];
IntStream.range(0, n).parallel().forEach(i -> {
for(int j=0;j<i;j++) {
directDistances[i][j] = directDistances[j][i] = ...;
}
});
//Use arr here...
arr = null; //arr no longer needed.
//This gives the error "Local variable defined in an enclosing scope must be final or effectively final."
I want to delete remove the reference to a large array by nulling the reference after I used it
Don't.
All implementations that I am aware of in the JVM world, will scan thread stacks to find out reachable objects. This means that scope of the method has nothing to do with how long an Object is kept alive. In simpler words:
void yourMethod(){
byte [] bytes = ....
// use bytes array somehow
// stop using the byte array
// .... 10_000 lines of code
// done
}
immediately after the line // stop using the byte array, bytes IS eligible for garbage collection. It is not going to be eligible after the method ends. scope of the method (everything between { and }) does not influence how much bytes is going to stay alive. here is an example that proves this.
The array becomes eligible for garbage collection at the latest when the method returns - you don't need to set it to null.
If you have a long method and are concerned that the array is kept around for the rest of it, the solution is to write smaller methods. Dividing the functionality among smaller methods may also improve readability and reusability.
If you can't or don't want to write smaller methods, introducing separate blocks in the method may help. Local variable declarations are local to the block, so this "trick" also lets you re-use a variable name in different blocks in the method.
void largeMethod() {
first: {
final int number = 1;
}
second: {
final int number = 2;
}
}
Technically, the array becomes eligible for garbage collection after its last use, which can be in the middle of the method - before the variable goes out of scope. This is explicitly allowed by section 12.6.1 in the language specification:
Optimizing transformations of a program can be designed that reduce the number of objects that are reachable to be less than those which would naively be considered reachable. For example, a Java compiler or code generator may choose to set a variable or parameter that will no longer be used to null to cause the storage for such an object to be potentially reclaimable sooner.
While the specification allows this optimization, it does not require it. If you find that the optimization is not being made in a particular situation and you need a better guarantee, splitting the big method into smaller methods will help.
Use AtomicReference ar = new AtomicReference () ; ar. set(arr) ;
This will provide you with an effectively final array
Then use ar.set() and ar.get() methods to modify the array

Life time of local variable in Java

public List<Map<String,class1>> methodName(String Parameter)
{
//create instance of List
List<Map<Strig,class1>> list1 = new ArrayList<Map<String,class1>>();
for(ArrayList arrayList : someGlobalList)
{
//create instance of class1
//Initialize class1 with values in arrayList
//Put this class1 as a value to tempMap which is created inside this loop
//Put that tempMap into List
}
return list1;
}
My doubt
I understand that we cannot guarantee garbage collection. But this question says that when we return a local reference that will not be garbage collected. In my case, class1 is a local Object. But I am returning list1. Is it safe to use those objects from the caller function as list1.get("key"). It will return the class1 Object. Can I safely use the class members?
An object is only eligible for garbage collection after the last reference to it is no longer reachable from your code.
Let's count the references to your newly created object. Each class1 object is only referenced from the list at the moment, so let's look at the references to the list itself.
You have one reference called list1.
Then you return a value. This creates a second reference, which is placed in the stack and passed up to the caller.
List<...> result = theObj.methodName("foo");
During that process the first reference (list1) is no longer accessible, but the reference that was returned back is still accessible - it will be assigned to the variable result in this case. So you still have one valid and accessible reference to the list. Therefore, every reference inside the list is also valid and accessible.
So yes, it is completely safe to use.
There are languages other than Java, where you can allocate an object in stack space. That is, the object itself is allocated locally. Returning a reference to such an object is unsafe as the stack frame is popped. Take this example in C, that returns a pointer to the beginning of a local array:
char *bad_string(void)
{
/* BAD BAD BAD */
char buffer[] = "local string";
return buffer;
}
But in Java, objects are always allocated in heap space (barring internal optimizations which are not visible to the programmer and are checked to be safe, as mentioned in the comments).
An object allocated by the new operator is never "popped", and always obeys the rules of garbage collection. Stack/local method space is only used for primitives and references, and you never get a reference to any of those, only to objects. Thus, if you have a reference to something, you can trust that its memory is safe.
Yes, you'll be able to access all the objects contained in the list object (list1) you are returning (including objects of type class1) as long as its reference is assigned to a reference variable in the method that called methodName.
This is because there is no such thing as a local object. Objects live in the heap (unlike local variables which live on the stack) and they will only be eligible for garbage collection if there are no more reachable references to it.
Yes. The moment list1 leaves the frame ( is returned by the function ), it and all of it's references stop being "local variables" and will not be candidates for garbage collection until there are no longer any references to "list1"
In my case, class1 is a local Object. But I am returning list1
If a reference leaks from a method, then that object can be used (safely? is again another question which is dependent on the exact definition of safe). In your case since you are returning list1, all local fields referenced by list1 (recursively) can be accessed without NPE (or the fear of them being GCed) because your list has a strong reference to those instances.
If you are talking about thread safety, then it depends on how many threads have access to this leaked reference(s).
You need to have only one reference. Objects referenced by this first referenced object will be free from GC as well.. and so on up the tree.

how does garbage collection with respect to Strings in Java?

I am reading about memory management in JVM and that if an object has no more references to it, it is garbage collected.
lets say, I have a program
public test {
public static void main(String[ ] args) {
String name = "hello";
for (int i =0 ; i < 5; i++) {
System.out.println(i);
}
}
}
As you can see, the String name is not used anywhere, so its reference is kept through out and not garbage collected.
now I have,
String name = "hello"
String name2 = name.substring(1,4)//"ell"
here again, the reference for hello must be present always, and cannot be garbage collected, since name2 uses it.
so when do these String or any objects get garbage collected, which have references but are obsolete, i.e. no longer used in code?
I can see one scenario where trimming down an array causes memory leak and hence setting its reference to null is a good way to garbage collect those obsolete references.
I can see one scenario where trimming down an array causes memory leak
and hence setting its reference to null is a good way to garbage
collect those obsolete references.
Strings are reference types, so all the rules for reference types with respect to garbage collection apply to strings. The JVM may also do some optimizations on String literals but if you're worrying about these, then you're probably thinking too hard.
When does the JVM collect unreferenced objects?
The only answer that matters is: you can't tell and it needn't ever, but if it does you can't know when that will be. You should never write Java code around deterministic garbage collection. It is unnecessary and fraught with ugliness.
Speaking generally, if you confine your reference variables (including arrays or collections of reference types) to the narrowest possible scope, then you'll already have gone a long way toward not having to worry about memory leaks. Long-lived reference types will require some care and feeding.
"Trimming" arrays (unreferencing array elements by assigning null to them) is ONLY necessary in the special case where the array represents your own system for managing memory, eg. if you are making your own cache or queue of objects.
Because the JVM can't know that your array is "managing memory" it can't collect unused objects in it that are still referenced but are expired. In cases where an array represents your own system for managing memory, then you should assign null to array elements whose objects have expired (eg. popped off a queue; J. Bloch, Essential Java, 2nd Ed.).
Technically, the JVM is not required to garbage-collect objects ever. In practice, they usually come behind a little while after the last reference is gone and free up the memory.
First, be aware that constants are always going to be around. Even if you assign a new value to name, the system still has a copy of "hello" stored with the class that it will reuse every time you hit that initializer statement.
However, don't confuse using an object for some sort of calculation with keeping a reference to it forever. In your second example, while "hello" is in fact kept around, that's just because it's living in the constant pool; name2 doesn't have any sort of "hold" on it that keeps it in memory. The call to substring executes and finishes, and there's no eternal hold on name. (The actual implementation in the Oracle JVM shares the underlying char[], but that's implementation-dependent.)
Clearing out arrays is a good practice because it's common for them to be long-lived and reused. If the entire array gets garbage collected, the references it holds get erased (and their objects garbage collected if those were the last ones).
Every variable in Java has a scope: The piece of code during which the variable is defined. The scope of a local variable like name in your example is between the brackets {} it is in. Thus, the name variable will be defined when the thread reaches the String name = "hello"; declaration, and will be kept alive until the main method is finished (because then the brackets the variable was in are closed).
Strings are a different story though than other variables. Strings are cached internally and may not actually be made available for the garbage collector yet.

regarding garbage collection and references

I have a question regarding references and garbage collector in java.
When calling a method with a parameter, let say an array, it is sent a copy of the reference of the array that is considered the parameter.
Hypothesis: the garbage collector is triggered exactly after calling the method, or when executing operations inside the method to the considered array.
Is now the same reference for the array in the calling method and in the called method, regardless of the operations and moves done by the garbage collector (the garbage collector can move the reference from eden to survivor 1)?
A simpler expression for the question: can you rely on this reference copy in order to use it as a mechanism for parameters sent 'by reference'?
Thank you very much!
Roxana
If you're trying to ask whether you can fake pass by reference like this:
// We'd like to pass x by reference...
String x = "hello";
String[] array = { x };
foo(array);
x = array[0];
...
static void foo(String[] array)
{
array[0] = array[0] + "foo";
}
... then yes, that will always work, and isn't affected by garbage collection.
I'd personally try to avoid it, but yes, it'll work :)
Note that unlike with real pass-by-reference, if the method throws an exception then the assignment after the method call won't occur, so you'll lose the "change".
Garbage collector removes object that cannot be accessed by any reference. In your example there are at least 2 references that can be used to access object. Therefore it will not be removed and you can be use references to access it.
Some garbage collectors work by finding objects with no references and reclaiming the space they occupy.
Others work by finding all objects with references, and moving them to a new object space. When all objects have been moved, the old object space is reclaimed. In that case, all the references are updated.

Does setting Java objects to null do anything anymore?

I was browsing some old books and found a copy of "Practical Java" by Peter Hagger. In the performance section, there is a recommendation to set object references to null when no longer needed.
In Java, does setting object references to null improve performance or garbage collection efficiency? If so, in what cases is this an issue? Container classes? Object composition? Anonymous inner classes?
I see this in code pretty often. Is this now obsolete programming advice or is it still useful?
It depends a bit on when you were thinking of nulling the reference.
If you have an object chain A->B->C, then once A is not reachable, A, B and C will all be eligible for garbage collection (assuming nothing else is referring to either B or C). There's no need, and never has been any need, to explicitly set references A->B or B->C to null, for example.
Apart from that, most of the time the issue doesn't really arise, because in reality you're dealing with objects in collections. You should generally always be thinking of removing objects from lists, maps etc by calling the appropiate remove() method.
The case where there used to be some advice to set references to null was specifically in a long scope where a memory-intensive object ceased to be used partway through the scope. For example:
{
BigObject obj = ...
doSomethingWith(obj);
obj = null; <-- explicitly set to null
doSomethingElse();
}
The rationale here was that because obj is still in scope, then without the explicit nulling of the reference, it does not become garbage collectable until after the doSomethingElse() method completes. And this is the advice that probably no longer holds on modern JVMs: it turns out that the JIT compiler can work out at what point a given local object reference is no longer used.
No, it's not obsolete advice. Dangling references are still a problem, especially if you're, say, implementing an expandable array container (ArrayList or the like) using a pre-allocated array. Elements beyond the "logical" size of the list should be nulled out, or else they won't be freed.
See Effective Java 2nd ed, Item 6: Eliminate Obsolete Object References.
Instance fields, array elements
If there is a reference to an object, it cannot be garbage collected. Especially if that object (and the whole graph behind it) is big, there is only one reference that is stopping garbage collection, and that reference is not really needed anymore, that is an unfortunate situation.
Pathological cases are the object that retains an unnessary instance to the whole XML DOM tree that was used to configure it, the MBean that was not unregistered, or the single reference to an object from an undeployed web application that prevents a whole classloader from being unloaded.
So unless you are sure that the object that holds the reference itself will be garbage collected anyway (or even then), you should null out everything that you no longer need.
Scoped variables:
If you are considering setting a local variable to null before the end of its scope , so that it can be reclaimed by the garbage collector and to mark it as "unusable from now on", you should consider putting it in a more limited scope instead.
{
BigObject obj = ...
doSomethingWith(obj);
obj = null; // <-- explicitly set to null
doSomethingElse();
}
becomes
{
{
BigObject obj = ...
doSomethingWith(obj);
} // <-- obj goes out of scope
doSomethingElse();
}
Long, flat scopes are generally bad for legibility of the code, too. Introducing private methods to break things up just for that purpose is not unheard of, too.
In memory restrictive environments (e.g. cellphones) this can be useful. By setting null, the objetc don't need to wait the variable to get out of scope to be gc'd.
For the everyday programming, however, this shouldn't be the rule, except in special cases like the one Chris Jester-Young cited.
Firstly, It does not mean anything that you are setting a object to null. I explain it below:
List list1 = new ArrayList();
List list2 = list1;
In above code segment we are creating the object reference variable name list1 of ArrayList object that is stored in the memory. So list1 is referring that object and it nothing more than a variable. And in the second line of code we are copying the reference of list1 to list2. So now going back to your question if I do:
list1 = null;
that means list1 is no longer referring any object that is stored in the memory so list2 will also having nothing to refer. So if you check the size of list2:
list2.size(); //it gives you 0
So here the concept of garbage collector arrives which says «you nothing to worry about freeing the memory that is hold by the object, I will do that when I find that it will no longer used in program and JVM will manage me.»
I hope it clear the concept.
One of the reasons to do so is to eliminate obsolete object references.
You can read the text here.

Categories