This code is a part of my class test -
class Bar { }
class Test
{
Bar doBar()
{
Bar b = new Bar(); /* Line 6 */
return b; /* Line 7 */
}
public static void main (String args[])
{
Test t = new Test(); /* Line 11 */
Bar newBar = t.doBar(); /* Line 12 */
System.out.println("newBar");
newBar = new Bar(); /* Line 14 */
System.out.println("finishing"); /* Line 15 */
}
}
At what point is the Bar object, created on line 6, eligible for garbage collection? Is it when doBar() completes?
All references to the Bar object created on line 6 are destroyed when a new reference to a new Bar object is assigned to the variable newBar on line 14. Therefore the Bar object, created on line 6, is eligible for garbage collection after line 14.
It isn't when doBar() completes because the reference in the doBar() method is returned on line 7 and is stored in newBar on line 12. This preserver the object created on line 6.
Questions of this kind seems to be very popular when teaching Java to beginners, but are complete nonsense. While an answer like this is great for making, whoever invented this question, happy, it’s not correct when digging deeper:
References to objects held in local variables do not prevent objects from being garbage collected. If the subsequent code does not touch them, these object may still be considered unreachable, which is not a theoretical issue. As demonstrated in “finalize() called on strongly reachable object in Java 8”, even the ongoing execution of a method of that object does not hinder its collection, if the instance is not subsequently touched.
Since in your example code, the objects do not hold any data, it’s obvious that they are never touched at all, which implies that they might get collected at any time, depending on the optimization state of the JVM. The code might also get optimized to a degree that it only performs the visible side effect of the two print statements, in other words, that the objects are never created at all.
This is backed by The Java® Language Specification, § 12.6.1. Implementing Finalization:
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.
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. …
Practically, since this is trivial short-running code inside a main method, the most common scenario would be that the code runs unoptimized, but no garbage collection will ever happen in that short run time.
This leads to the other reason why asking such questions is nonsense. It might be challenging to find the right points when an object is naively considered unreachable, it’ll be impossible to guess when and how the optimizer influences the outcome, but the entire purpose of the garbage collection is that the developer doesn’t have to worry about that.
After assignment at lin 14 is executed. At that point there is no references to Bar object from line 6 exists anymore.
I'd agree with jiltedpotato (It would be after line 14). An object is eligible for garbage collection, when all references to it are lost or discarded.
Take a look at: When Is The Object Eligible For Garbage Collection?
As simple as when there is no reference to an object will be eligible for garbage collection but when will it exactly be collected is dependent on GC algo.
Related
Suppose we have a program like this:
void main() {
// Point 0
BigThing bt = new BigThing();
// Point 1
WeakReference<BigThing> weak = new WeakReference<>(bt);
// Point 2
doSomething(weak);
// Point 3
}
void doSomething(...) { ... }
We know that the weak reference to the BigThing object cannot prevent the object from being garbage collected when it becomes no longer strongly reachable.
My question is about the local variable bt which is a strong reference to the BigThing object. Does the object become not-strongly-reachable at point 2 (just before calling doSomething()) or at point 3 (end of block scope)?
The answer to this question will affect whether the call to doSomething() is guaranteed to be able to access the live BigThing object, or whether the underlying object can die during the function call.
I am uncertain because you could argue that after point 2, the local variable bt is never read or written anymore, so the variable is effectively dead and the pointer value can be discarded. This "optimization" would be valid if all references were strong, but the reasoning falls apart when the notions of soft, weak, and phantom references are introduced, and finalizers as well. Also as an analogy, because C++ has destructors, a value must be destructed at the end of the scope, and cannot be moved ahead to the point of last usage.
I would say the object is collectable at point 2, going by the following language in JLS section 12.6.1:
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.
Since the bt variable will no longer be used after point 2, Java is free to clear that variable, rendering the BigThing object only weakly reachable.
Java 9 introduces Reference.reachabilityFence to solve this case, which of course also implies that it does exist in the first place.
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.
I just read this article: The Truth About Garbage Collection
In section "A.3.3 Invisible" it is explained how and when an object gets into the invisible state.
In the below code, the object assigned to the variable foo will become invisible after leaving the try/catch block and will remainly strongly referenced until the run method exits (which will never happen, because the while loop runs forever).
public void run() {
try {
Object foo = new Object();
foo.doSomething();
} catch (Exception e) {
// whatever
}
while (true) { // do stuff } // loop forever
}
It is stated in this article:
However, an efficient implementation of the JVM is unlikely to zero
the reference when it goes out of scope.
Why is that not efficient?
My attempt at an explanation is as follows:
Say the stack for this method contains four elements, with the now invisible object being at the bottom.
If you want to collect the object instantly, you would have to pop and store three elements, pop and discard the fourth element and then push the three still valid elements back onto the stack.
If you collect the invisible object after control flow has left the run method, the VM could simply pop all four elements and discard them.
The local variables are not on the operand stack, but in the local variables area in the activation frame, accessed, in the case of references via aload and astore bytecodes and zeroing a local variable does not involve any pushing and popping.
Zeroing is inefficient because it is not needed:
it would not cause an immediate garbage collection cycle
the zero may soon be overwritten by another value as dictated by the logic of the program.
going out of the scope means that the local variable is no longer part of the root set for garbage collection. As such what value it held immediately before going out of scope - zero or a valid reference - is immaterial; it won't be examined anyway.
EDIT:
Some comments on the last statement.
Indeed, at a bytecode level there are no scopes and a local variable slot may remain a part of the root set until the method returns. Of course, a JVM implementation can determine when a local variable slot is dead (i.e. all possible paths to method return either don't access the variable or are stores) and don't consider it a part of the root set, but it is by no means required to do so.
The very simple answer is b/c is inefficient.
There are many garbage collector algorithms and some may aggressively collect. Some compilers do allocation on the stack but the most obvious in your case is: doSomething() may actually keep (leak) a reference to the object elsewhere.
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.
In what situations in java is explicit nulling useful. Does it in any way assist the garbage collector by making objects unreachable or something? Is it considered to be a good practice?
In Java it can help if you've got a very long-running method, and the only reference to the an object is via a local variable. Setting that local variable to null when you don't need it any more (but when the method is going to continue to run for a long time) can help the GC. (In C# this is very rarely useful as the GC takes "last possible use" into account. That optimization may make it to Java some time - I don't know.)
Likewise if you've got a member field referring to an object and you no longer need it, you could potentially aid GC by setting the field to null.
In my experience, however, it's rarely actually useful to do either of these things, and it makes the code messier. Very few methods really run for a long time, and setting a variable to null really has nothing to do with what you want the method to achieve. It's not good practice to do it when you don't need to, and if you do need to you should see whether refactoring could improve your design in the first place. (It's possible that your method or type is doing too much.)
Note that setting the variable to null is entirely passive - it doesn't inform the garbage collector that the object can be collected, it just avoids the garbage collector seeing that reference as a reason to keep the object alive next time it (the GC) runs.
In general it isn't needed (of course that can depend on the VM implementation). However if you have something like this:
private static final Map<String, String> foo;
and then have items in the map that you no longer need they will not be eligible for garbage collection so you would need to explicitly remove them. There are many cases like this (event listeners is another area that this can happen with).
But doing something like this:
void foo()
{
Object o;
// use o
o = null; // don't bother doing this, it isn't going to help
}
Edit (forgot to mention this):
If you work at it, you should find that 90-95% of the variables you declare can be made final. A final variable cannot change what it points at (or what its value is for primitives). In most cases where a variable is final it would be a mistake (bug) for it to receive a different value while the method is executing.
If you want to be able to set the variable to null after use it cannot be final, which means that you have a greater chance to create bugs in the code.
One special case I found it useful is when you have a very large object, and want to replace it with another large object. For example, look at the following code:
BigObject bigObject = new BigObject();
// ...
bigObject = new BigObject(); // line 3
If an instance of BigObject is so large that you can have only one such instance in the heap, line 3 will fail with OutOfMemoryError, because the 1st instance cannot be freed until the assignment instruction in line 3 completes, which is obviously after the 2nd instance is ready.
Now, if you set bigObject to null right before line 3:
bigObject = null;
bigObject = new BigObject(); // line 3
the 1st instance can be freed when JVM runs out of heap during the construction of the 2nd instance.
From "Effective Java" : use it to eliminate obsolete object references. Otherwise it can lead to memory leaks which can be very hard to debug.
public Object pop(){
if(size == 0)
throw new EmptyStatckException();
Object result = elements[--size];
elements[size] = null; //Eliminate Object reference
return result;
}
If you are nulling an object that is about to go out of scope anyway when your method block closes, then there is no benefit whatsoever in terms of garbage collection. It is not unusual to encounter people who don't understand this who work really hard to set a lot of things to null needlessly.
Explicit nulling can help with GC in some rare situations where all of the following are true:
The variable is the only (non-weak) reference to the object
You can guarantee that the object will no longer be needed
The variable will stay in scope for an extended period of time (e.g. it is a field in a long-lived object instance)
The compiler is unable to prove that the object is no longer used, but you are able to guarantee this though your superior logical analysis of the code :-)
In practice this is quite rare in good code: if the object is no longer needed, you should normally be declaring it in a narrower scope anyway. For example, if you only need the object during a single invocation of a method, it should be a local variable, not a field in the enclosing object.
One situation where explicit nulling is genuinely useful: if null is used to indicate a specific state then setting to a null value is sometimes going to be necessary and useful. Null is a useful value in itself for a couple of reasons:
Null checks are extremely fast, so conditional code that checks for null is typically more efficient than many alternatives (e.g. calling object.equals())
You get an immediate NullPointerException if you try to dereference it. This is useful because it is good Fail Fast coding style that will help you to catch logic errors.
See also WeakReference in J2SE.