A question about GC - java

This is a quesiton taken from a java exam,
How many objects are eligible for gabage collection at #1 ?
public class Main {
Integer x = 32768;
public static void main(String[] args)
{
Main m = new Main();
m = null;
// #1
}
}
I thought it just collect Integer x, does GC even collect the Main object m?

Yes, it does collect Main object. Since integer is neither a separate object by itself (it's a member of Main) not a pointer it won't be collected separately but only as a part of Main.

Two objects may be deleted by the garbage collector.
The object assigned to m is not reachable any more, nor is the Integer inside Main.
Edit: You can ask yourself: "Is it possible that I access the object in some way at this point?" If the answere is "No", the garbage collector may delete it.

One bit of confusion you may be having is that the main method can be called without there even being a main object in existence. That is because it is a static method. Similarly, the "Integer x" only exists as a field in a main object. So when you create a new Main object m you also create the integer m.x as part of m. Then when you set m to null the object that was previously referred to by m is garbage and can be collected.
Now, when will it be collected is a totally different question. There are really are no guarantees; however, since its use was so localized it will almost certainly be taken care of at the next minor collection/scavenge/pick-your-favorite'-terminology.

It could. There is no reference to it anymore, so it is eligible for garbage collection.

The instance of Main is eligible for garbage collection and normally the Integer will also be eligible. But the Integer instance can also be cached by the Integer class if configured to do so (see this answer).
Normally only integers between -128 and 127 are cached when using Integer#valueOf(int) (used for autoboxing) but the upper limit can be increased by setting the system property java.lang.Integer.IntegerCache.high

My observations using a recent OpenJDK have shown that only once a method exits do any references it orphaned actually get collected. I did not expect this at all, but it's what happened. Extracting those lines of code into another method, which would then return back to main(), did allow the instance to be collected.
I think this is a dumb question. (EDIT: I mean the exam question! Not insulting the submitter!) It's all in how you define "eligible". In my case, I'd say once there were no references left, the instance was eligible to be collected, it's just that it never would actually be collected until sometime after the method returns.

Related

Weak Reference and strong Reference

I have a very basic question regarding weak reference and strong reference in Java.
In general Java programming we generally do not create weak reference of object, we create normal strong reference but when we are done with that object we assign null to that object with the conception that, that object will be collected by GC next time.
Is that my understanding is wrong?
After reading some of the articles, it looks like, object is collected by GC If it is null or not referred anywhere if only it has weak reference. I am confused.
In other word what is the difference between these two code snippets, in respect to Java GC?
Snippet 1
Counter counter = new Counter(); // strong reference - line 1
WeakReference<Counter> weakCounter = new WeakReference<Counter> (counter); //weak reference
counter = null;
Snippet 2
Counter counter = new Counter(); // strong reference - line 1
counter = null;
In both cases, counter will be eligible for garbage collection. Even if you use SoftReference, it will be eligible for GC, but it will only be collected reluctantly. (That is, a SoftReference encourages the GC to leave the object in memory, but still allows it to be collected.)
Only hard references force the GC to leave objects alone.
Normally you only need to assign null to a reference if the reference has longer life than you want for the object. Once a hard-reference variable goes out of scope, it is no longer reachable from live code so its hard reference will not prevent the GC from collecting the object.
Note also that there's no guarantee as to when objects eligible for collection will actually be collected by the GC. It may be on the next GC cycle or maybe not. It depends heavily on the implementation of the GC. The only thing you can say for sure is that all eligible objects will be collected before the VM throws an OutOfMemoryError.
The difference is that if I remeber correctly,
The First code snippit assigns the value null to the object counter after it has been assigned to weakCounter. So therfor weakCounter still has the reference to the old counter without the reference to counter being updated. But the counter is still collected by the compiler, even though the weakCounter is assigned to an object reference of Counter
In the second code example, the counter goes from being assigned to a object to a null value letting java know "hey you can collect me in the garbage!"
Hope this made sense and it helped your understanding if some of my facts are wrong please feel free to tell me where I am mistaken :)
The two are essentially equivalent, save for the fact that you might be able to reference the object through the WeakReference if you do so before GC collects it.
The purpose of the WeakReference is so you can have it stashed somewhere (eg, some sort of search index) and not worry about having to clear it if you are done with the object and wish to null any "strong" references (so that the object may be collected and the space reused). If you used an ordinary strong reference you'd have to be sure to clear it or the object would hang around forever.
(SoftReferences, as mentioned by Ted Hopp, are similar in mechanics, except that GC will only collect the referenced objects if storage is tight. This makes them suitable for things like cached internet pages.)

Where does return value go in java if no variable assigned to accept it?

Let's say a method returns some value, but when I call it, I don't assign any variable to accept this RV. Then where does it go? Will GC collect it? Would it be a problem if I use this kind of method tons of times in my code?
Then where does it go?
It doesn't go anywhere. The value / reference is simply discarded. It is as if you assigned it to a local variable that immediately goes out of scope.
Will GC collect it?
It will be garbage collected when the garbage collector detects that it is unreachable. In your example, the method doesn't put the object reference anywhere else, so it will be unreachable immediately.
Note that even if the object is immediately unreachable, it may take some time for the GC to notice this and collect it. (But that's not a bad thing. It is considerably more efficient to forget the object reference and deal with later than to try to reclaim the space immediately.)
Would it be a problem if I use this kind of method tons of times in my code?
Not necessarily. The example code is not doing anything useful, and hence the overheads of allocating the object and then garbage collected are simply a waste of resources. But if it was doing something useful, the overheads are not likely to be a problem. (In ideal conditions, allocating and garbage collecting an object is cheap in Java.)
Unnecessary allocation can be a problem in some cases though:
If you are running with a heap that is too small for the application's working set of objects, the overheads can ramp up.
HotSpot's default "throughput" GC will "stop the world" while the GC is running, so excessive allocations will increase the number o f GC pauses that you experience. (This may or may not matter ... depending on the application.) You can mitigate this by using CMS or G1 as your collector, but that introduces overheads in other areas.
Assuming the value isn't referenced anywhere else, it will be garbage collected
Will GC collect it?
Yes. Since there would be no live reference to the Object returned it would be eligible for GC.
Would it be a problem if I use this kind of method tons of times in my code?
It should not. All the returned Objects will be GCed.
There's nothing that special about a return value over a local variable, consider:
public Object example {
Object a = new Object();
return new Object();
}
Then if I briefly explain how return values work:
When a method starts a new "stack-frame" is pushed on to the stack. It is an area of memory that includes parameter and local variable storage including the return value. It also knows where to return to.
When the method executes, new objects are created on the heap and only pointers to them exist in the stack.
After the code for the method has been run the value of a non-void return method is passed back to the calling method and stored in it's stack frame.
If a non-void return method's value isn't required by the caller, then it will share the same fate as any other local variable in that stack frame. And that is it's value is no longer used. If that value was an object, then garbage collection is already aware of it and is now able to ascertain that it is not referenced and can be collected.

Garbage Collection and InComplete Constructed Object

This may be a very naive Question?
Suppose i have Class Something like this
class SlowConstructor {
private final int a;
private final String unReachableString;
public SlowConstructor(String random) {
unReachableString = "I am not reachable will GC will collect me " + random;
Thread.sleep(1000*3600); // ignoring Exception check for readbility
a = 100;
Thread.sleep(1000*3600);
}
}
So my question is if i create Many Objects of SlowConstructor (let say 50 in diff threads) and as you can see each Constructor will take two hours to complete. The String reference in SlowConstructor unReachableString is not reachable from any code for around two hours. If GC runs during this two hours will it not collect unReachableString ref ?. I assume it will not be Garbage Collected but then why? From where unReachableString is reachable ?
The String reference in SlowConstructor unReachableString is not reachable from any code for around two hours.
Incorrect. The SlowConstructor object is immediately reachable from the thread that is in the process of constructing it. So, therefore, is the string.
So that means that the String object won't be garbage collected before the constructor completes.
(And in fact, the string object corresponds to a String literal, and is therefore also reachable from the code (any code!) that assigns or applies a method to the literal.)
The concept of reachability includes any mechanism by which any current or future execution could use the object in question. That includes cases where the object hasn't been assigned to a named variable or array element ... yet.
As other have said GC is not going to affect a half-constructed object. But why? GC necessarily proceeds from a maximal set of root pointers. Anything that can be reached from these roots is "protected" from GC. This is either my marking as in mark-and-sweep collectors or by copying to a new active generation (arena) in a copying collector. Roots consist of the runtime stack, machine (virtual or physical) registers, and global pointers. When the constructor starts running, a pointer to the newly allocated record will be created. Either it will be a root or accessible from a root. So the GC will not collect it. Since the class instance under construction is accessible from a root, so is the string you're referring to. Therefore it can't be collected either.
So long as the threads weren't interrupted, your object will (eventually) instantiate, and (eventually) contain a value for unReachableString.
Strings are interned, and would be subject to garbage collection only if nothing referred to it - kind of like how garbage collection works now. The half-constructed object does refer to the interned string, so it would not be yet eligible for garbage collection.
I'm willing to bet that having fifty or so instances of this type floating around* wouldn't make a difference either - you then have fifty or so references to this string literal, and it wouldn't be yet eligible for garbage collection until these instances were eligible for garbage collection themselves.
*: OH GOD NO PLEASE DON'T DO THIS IN ACTUAL CODE PLEASE
It will not and should not be garbage collected. Sleeping thread is still a live thread.
Reachable in GC context means the following: if we go through the Stack will we find a reference pointing to this object (memory space) on the Heap.
In you case the answer is yes.
your logic is not correct, if thread is still alive it is in scope of method SlowConstructor. So JVM thinks that unReachableString string can be used so Garbacge Collection does not touch that reference.
According to the code you can assume that unReachableString is not used so it has to be Garbage Collected but JVM does not have intelligent logic to know the next. It just look at the scope of method and object reference.

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

Does variable = null set it for garbage collection

Help me settle a dispute with a coworker:
Does setting a variable or collection to null in Java aid in garbage collection and reducing memory usage? If I have a long running program and each function may be iteratively called (potentially thousands of times): Does setting all the variables in it to null before returning a value to the parent function help reduce heap size/memory usage?
That's old performance lore. It was true back in 1.0 days, but the compiler and the JVM have been improved to eliminate the need (if ever there was one). This excellent IBM article gets into the details if you're interested: Java theory and practice: Garbage collection and performance
From the article:
There is one case where the use of explicit nulling is not only helpful, but virtually required, and that is where a reference to an object is scoped more broadly than it is used or considered valid by the program's specification. This includes cases such as using a static or instance field to store a reference to a temporary buffer, rather than a local variable, or using an array to store references that may remain reachable by the runtime but not by the implied semantics of the program.
Translation: "explicitly null" persistent objects that are no longer needed. (If you want. "Virtually required" too strong a statement?)
The Java VM Spec
12.6.1 Implementing Finalization
Every object can be characterized by two attributes: it may be reachable, finalizer-reachable, or unreachable, and it may also be unfinalized, finalizable, or finalized.
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.
Discussion
Another example of this occurs if the values in an object's fields are stored in registers. The program may then access the registers instead of the object, and never access the object again. This would imply that the object is garbage.
The object is reachable if it can be involved in any potential continuing computation. So if your code refers to a local variable, and nothing else refers to it, then you might cause the object to be collected by setting it to null. This would either give a null pointer exception, or change the behaviour of your program, or if it does neither you didn't need the variable in the first place.
If you are nulling out a field or an array element, then that can possibly make sense for some applications, and it will cause the memory to be reclaimed faster. Once case is creating a large array to replace an existing array referenced by a field in a class - if the field in nulled before the replacement is created, then it may relieve pressure on the memory.
Another interesting feature of Java is that scope doesn't appear in class files, so scope is not relevant to reachability; these two methods create the same bytecode, and hence the VM does not see the scope of the created object at all:
static void withBlock () {
int x = 1;
{
Object a = new Object();
}
System.out.println(x+1);
}
static void withoutBlock () {
int x = 1;
Object a = new Object();
System.out.println(x+1);
}
Not necessarily. An object becomes eligible for garbage collection when there are no live threads anymore that hold a reference to the object.
Local variables go out of scope when the method returns and it makes no sense at all to set local variables to null - the variables disappear anyway, and if there's nothing else that holds a reference the objects that the variables referred to, then those objects become eligible for garbage collection.
The key is not to look at just variables, but look at the objects that those variables refer to, and find out where those objects are referenced by your program.
It is useless on local variables, but it can be useful/needed to clear up instance variables that are not required anymore (e.g. post-initialization).
(Yeah yeah, I know how to apply the Builder pattern...)
That could only make some sense in some scenario like this:
public void myHeavyMethod() {
List hugeList = loadHugeListOfStuff(); // lots of memory used
ResultX res = processHugeList(hugeList); // compute some result or summary
// hugeList = null; // we are done with hugeList
...
// do a lot of other things that takes a LOT of time (seconds?)
// and which do not require hugeList
...
}
Here it could make some benefit to uncomment the hugeList = null line, I guess.
But it would certainly make more sense to rewrite the method (perhaps refactoring into two,
or specifying an inner scope).
Setting an object reference to null only makes it eligible for garbage collection.
It does not necessarily free up the memory,which depends on when the garbage collector runs(which depends on JVM).
When the garbage collector runs,it frees up the heap by deleting only the objects which are eligible for garbage collection.
It is a good to have. When you set objects to null, there is a possibility that the object can be garbage collected faster, in the immediate GC cycle. But there is no guaranteed mechanism to make an object garbage collected at a given time.

Categories

Resources