When does this object become eligible for garbage collection? - java

I have this piece of code, and I am confused about when the Object o becomes eligible for garbage collection in Java.
public class JustSo
{
public static void main(String[] args)
{
for(int i=0;i<4;i++)
{
Object o=new Object();
//o.doSomething();
}
System.out.println("DONE");
}
}
Since it is inside a loop(or any block for that matter), it will become eligible at the end of the loop right?
But I found an answer on a reliable developer site(Don't want to disclose where) that says the earliest the object becomes eligible is at the print statement.
Please clarify.

When it becomes out of scope, so after each iteration of the for loop. An object is eligible for garbage collection when it is no longer reachable, this occurs in 2 situations.
The object no longer has any references point to it.
All references to the object have gone out of scope.
The latter is the situation for the object in question, and it the object's reference is out of scope after the for loop. Prior to the print statement.

As the oracle documentation about the garbagecollector says:
Automatic garbage collection is the process of looking at heap memory, identifying which objects are in use and which are not, and deleting the unused objects. An in use object, or a referenced object, means that some part of your program still maintains a pointer to that object. An unused object, or unreferenced object, is no longer referenced by any part of your program. So the memory used by an unreferenced object can be reclaimed.
This means as soon as an Object isn't referenced from any other Object or is out of scope, it will be marked for deletion. In this case, the reference is out of scope, each time the loop starts again (just before every increment). Thus each object will be marked for deletion at the end of the loop (before the next loop-repetition).

Since you are not saving the reference into some outer-scope variable,and creating new instance each time as soon as single iteration complete, its eligible for garbage collection.
So when you came out of loop, all the objects created inside eligible for GC.
May be you confused with author wording here. Consider below code
for(int i=0;i<4;i++)
{
Object o=new Object();
//o.doSomething();
} -----> objects ready for GC here.
// some other code
// some other code
System.out.println("DONE");

Each time around the loop, around the time when i++ happens, the object will become eligible for GC.

Related

No OutOfMemory Error for Strongly referenced objects - Why?

From this post Strong references never be garbage collected, With this understanding I assume if we create a infinite Strong Reference objects in memory then it must throw OutOfMemory error.
However, When I ran below dummy program it never through OutOfMemory error although I have created infinite objects in while loop.
public class Test2 {
public static void main(String[] args) {
while (true) {
Test2 obj = new Test2();
System.out.println(obj);
}
}
}
Please help me understand if strong referenced objects are never garbage collected then how come there is no OOM error.
You don't keep the strong reference to the object. Each time you go through the loop, there's no longer any reference to the object created in the last iteration, and it is eligible for garbage collection.
Objects are not garbage collected if they are reachable from a GC-root-object via strong references. In your example only one Test2-object is reachable from your thread at any time. The strong reference obj is updated each iteration and thus the previous Test2-object is no longer strongly referenced from anywhere and can be garbage collected.
If you want to create an OOM you might add the new objects to a List and keep them there.

Java GarbageCollection and Collections

Say I do something like this:
List<Stuff> methodA() {
List<Stuff> all_the_stuff_to_do = new ArrayList<>();
all_the_stuff_to_do.add(new Stuff("important"));
all_the_stuff_to_do.add(new Stuff("not important"));
return all_the_stuff_to_do;
}
List<Stuff> methodB() {
List<Stuff> important_stuff_to_do = new ArrayList<>();
Stuff important = methodA().get(0);
// at this point Stuff("not important") is not reachable anymore
// since I have no reference to the list that contains it left
important_stuff_to_do.add(important);
return important_stuff_to_do;
}
void methodC() {
... do a happydance ...
List<Stuff> stuff_to_do = methodB();
... look sad because now I got important stuff to do ...
}
***** EDIT *****
Better clarification and simplified code
To Clarify:
When exiting methodA() I got a reference of a list with two objects Stuff("important") and Stuff("not important")
I add the reference to Stuff("important") to a list in methodB().
At this point the Object Stuff("not important") is not reachable anymore.
Also the List in methodA() is not reachable anymore.
But the List still contains a reference to an Object that is indeed reachable, namely Stuff("important").
When will the all_the_stuff_to_do List be cleared and when the Stuff("not important") Object?
Will it be directly after the Call to MethodA? Or will it be at the end of MethodB? Or never since it contains a reference to the Stuff("important") Object that is still active till the end of the program?
Will (all_the_stuff_to_do be garbage collected) directly after the Call to MethodA?
Or will it be at the end of MethodB? Or never since it contains a reference to the Stuff("important") Object that is still active till the end of the program?
Garbage collection is generally done on a low priority thread. If nothing else is being done, the garbage collector may run.
If the VM is low on, or out of, memory, the garbage collector may run immediately as the highest priority thread, since it needs to recover memory for the program's immediate need.
So, will it be collected directly after the call to MethodA? No. Will it get collected after the call to get(0)? Possible, but unlikely. At the end of MethodB? Possible, but unlikely. Still active at the end of the program? Possible, but only likely if the program never ran out of memory and never became idle.
The fact that the list contains a copy of "Stuff("important") Object" is irrelevant to whether the list gets collected. If no accessible objects reference the list, the list is eligible for garbage collection.
Will the list get #clear()'d during collection? No, there is no need. If it was a user defined collection, the clear method could do anything, including add another reference to the list, which would mess up the garbage collection. Instead, it is just collected, and objects the list refer to are referenced one less time. That include "Stuff("important") Object" ... It's reference count will get decremented, but since a reference still exists, it won't be cleared.
The collection contains references to the objects that you have added. Until that is no longer reachable or you remove the objects from the collection, they will be reachable. Can you think of a way programs could work reliably if it were otherwise?
In your scenario new Stuff("important") here new keyword is responsible to making an object and reference of this Stuff Object hold by the collection List <Stuff> important_stuff_to_do. Now this collection will hold the reference of the two object that you made .
As per Collection definition all we know that Collection is a group of multiple Object of same type of Objects as a single Entity.
So, No Garbage Collection will be perform because here these two objects are still reachable.
new Stuff("important")
new Stuff("not important")
Note:- Garbage Collection performs only objects which is completely unreachable (One kind of Orphan). Here No Object is getting orphan because Collection never makes the copy / cloing of the objects which is added .
Conclusion :- No Garbage will be performed in this scenario. Thank you

At what line can this object be considered to be garbage collected. Java

So my understanding is at line 1, a new object is created and it is referenced by obj. At line 2, obj is referencing to another new object. so the object which we created at line 1 is eligible for garbage collection because it is not referenced by any instance. But the answer from test question is at line 3. Reason? Is the answer correct?
Object obj = new Object(); //line 1
obj = new Object(); //line 2
obj = null; //3
Edit: it is asking when the object created at line 1 can be eligible for garbage collection.
In the real world this question (as posed by the title) has no clear answer.
aggressive dead code elimination could eliminate the first object allocation since it never becomes visible
a modified Object Class (e.g. via bytecode instrumentation or bootstrap classloaders) could resurrect itself on finalization or hold onto additional references indefinitely
garbage collection is asynchronous and happens at an indefinite point in the future, so while an object may be inaccessible from java code it cannot be "considered" garbage collected until it actually has been garbage collected.It might show up in a heap dump after all, which can be relevant if it contained security-sensitive data
I know it's supposed to be an academic question with a simple answer, but there are so many assumptions to make that I could rule-lawyer you any answer you want into existence.
Even if we don't pull any rabbits out of our hat the answer would still depend on whether "at line X" means before or after the execution of that
The garbage collector is checking for live objects and discarding anything that is not. When you create obj, you define it's type because that allows the compiler to know how much space to allot for that address, because something of Type Object will exist there. When the second line executes, new is creating an entirely new instance of the object and you are assigning its address to obj. So after reassigning obj to reference a new object, the old one still exists, but is no longer referenced. It would potentially be marked for collection as it occupies space in the heap, but is no longer active. The same happens with line 3, except, as mentioned previously, you are assigning it an address of null, and no new object is being created. So what used to be referenced by obj are now dead objects and the garbage man takes them away.

Object creation without vairable assignment

What happens to an object that is created but not assigned to a variable? Is it garbage collected immediately?
In one of my programs, I'm testing if creating a particular object throws an exception. In the catch block I'm returning false to the function call if an exception is thrown (I know this isn't the best way to do it).
But in either case if I do this:
new Object();
What is happening in memory?
That depends on the object's constructor. If it stores it's own reference in another object, it won't be destroyed, of course. Otherwise it is destroyed when GC collects the next time.
Such object has no references pointing on it, so it become available for garbage collection and will be destroyed at next GC.
The object will be eligible for GC when the control goes out of the scope(method or block) where it is declared.

When does object go out of scope if no variable is assigned?

When does the object of type list, occupying memory, become eligible for garbage collection, Also where is the variable that holds reference to the list ? In the case of code below, there was no variable assigned to it.
CASE 1:
for (Integer i : returnList()) {
System.out.println(i);
}
In case of a code like:
CASE 2:
List list = returnList();
for (Integer i : list) {
System.out.println(i);
}
list = null;
We can take control of GC, Is there any ways to take care of that in the first case when no variable was assigned ?
To summarize:
What is the mechanism of referrence, without a reference variable to list is case 1?
Does list get eligible for GC'd when stack frame is popped ?
Any way to speed up the eligibility for GC'ing ?
What is the mechanism of referrence, without a reference variable to list is case 1?
There is an implicit reference to the list. This can be seen by understanding that enhanced for like that is translated into:
for(Iterator e = returnList().iterator(); e.hasNext(); ) {
Integer i = (Integer)e.Next();
System.out.println(i);
}
Here, e has a reference to an iterator on returnList, which itself has a reference to returnList. Thus, returnList is rooted as long as e is rooted which is only true while control is in the for loop. When control leaves the for body, e is eligible for collection, so returnList is eligible for collection.
Of course, all of this is assuming that
The owner of returnList isn't maintaining a reference to its return value.
The same list hasn't been returned to another caller and that other caller isn't maintaining a reference to the same list.
Does list get GC'd when stack frame is popped ?
Not necessarily. It will be eligible for collection when the JVM can determine that the referrent has no rooted references to it. Note that it does not necessarily immediately get collected.
Any way to speed up GC in case 1.
It can't be collected any sooner than control leaving the for loop. It might be collected after control leaves the for loop. Let the JVM worry about this.
Note that you can attempt a manual garbage collection via
System.gc();
but note that this might exhibit worse behavior because if it triggers a garbage collection, it might be a full garbage collection. Note that the JVM can ignore this request. You might be wasting a lot of CPU cycles here. Note that on a system with infinite memory, the garbage collector never needs to run. On such a system, requesting the garbage collector could be a complete waste of CPU cycles if the garbage collector obeys your request.
Let the JVM manage the garbage collections. The algorithms for it are highly tuned.
From SCJP page 256-257
The garbage collector does some magical, unknown operations, and when
it discovers an object that can't be reached by any live thread,it
will consider that object as eligible for deletion, and it might even
delete it at some point. (You guessed it; it also might not ever
delete it.) When we talk about reaching an object, we're really
talking about having a reachable reference variable that refers to the
object in question. If our Java program has a reference variable that
refers to an object, and that reference variable is available to a
live thread, then that object is considered reachable.
Setting an object to NULL might help to fasten when the GC deletes the object but it might as well not, you don't have control over that. The JVM will run GC when it senses that memory is running low and you can manually ask it to do so but nothing is guaranteed.
What is the mechanism of reference, without a reference variable to
list is case 1?
see next answer.
Does list get GC'd when stack frame is popped ?
The list is created on the heap - but if the only reference to it was on the stack it is eligible to be collected by GC. That doesn't mean that it'll happen any time soon though.
Any way to speed up GC in case 1.
You can't "speed up" GC, even by calling System.gc(); you're only "suggesting" that the GC can to do its work - again, it won't necessarily happen any time soon.
There's a lot of sense behind it too: say that your program has 2GB of memory to use and is currently using only 2KB - it does not justify GC stopping your program from running and clean the memory only because some objects are eligible for deletion.
You cannot take control of GC.It is managed by JVM. What you can manage is what objects should be available for garbage collection. Although , you can find out when garbage collector will run using finalize method. It is always called before an object is deleted
public class Demo{
static void create()
{
Demo o = new Demo();
}
public void finalize()
{
System.out.println("GC called");
}
public static void main (String ...ar)
{
for (long i=1;i<900000;i++) //Try changing values here
{
create();
}
}
}
Objects created inside the methods are available for GC when method is returned(just like local variables exist for duration of method).However if the method returns an object, it will not be avialble for garbage collection
public class Demo{
public void getDate()
{
Date o = new Date();
StringBuffer d = new StringBuffer(o.toString());
System.out.println(d);
return o;
}
public static void main (String ...ar)
{
Date x= getDate();
}
}
In the above code, object d is available for GC when the method returns. But object o will not be available for collection

Categories

Resources