public class App1
{
public static void main(String[] args)
{
Point point_1 = new Point(5,5);
Point point_2 = new Point(7,8);
Circle circle_1 = new Circle(point_2, 10);
point_1 = null;
point_2 = null;
}
}
How many object references exist after this code has executed? Why?
After this code has executed, exactly none, since it will have exited :-)
If you mean at the point just before exit, there's a reference on the stack to your circle and a reference in your circle to the second point, assuming the constructor stores it.
Despite formulation problems, the snippet is actually quite instructive on certain aspects of garbage collectibility. Let's take a look at it line-by-line.
Point point_1 = new Point(5,5);
So we've declared a reference variable point_1, and it points to a new Point. Let's assume for now that the constructor of Point doesn't do anything fancy and simply set fields final int x, y with the given values.
Thus, we now have something like this:
Now let's take a look at the next line:
Point point_2 = new Point(7,8);
Now we have something like this:
Now let's take a look at the next line:
Circle circle_1 = new Circle(point_2, 10);
Here again we don't quite know how Circle is implemented, but it's reasonable to assume that it has a final Point center and final int radius fields, and with the Point center specifically, it simply sets the reference to the given Point (i.e. no defensive copying since Point is immutable).
So now we may have something like this:
Then with the next two statements, we set point_1 and point_2 to point to null respectively:
point_1 = null;
point_2 = null;
So now we have something like this:
We can now observe that:
The object [aPoint(5 5)] is no longer reachable
The object [aPoint(7 8)], though no longer refered to by point_2, is still refered to by [aCircle(10)].center.
Garbage collectibility is defined by whether or not an object is reachable by a live reference. The object [aPoint(5 5)], we can strongly assume (based on how we think Point is implemented), is no longer reachable, so it is eligible for collection (it's a garbage! No one can "pick it up" now!).
On the other hand, the object [aPoint(7, 8)] is still referred to by [aCircle(10)].center, so we can say that it's NOT eligible for collection (it's not a garbage! Someone is still "hanging on" to it!).
Moral
So no, definitely setting a reference to null does NOT make the object previously being referred to automatically eligible for collection. It depends on the object itself, whether or not there are any references to the object.
Certainly, though, setting a reference to null CAN help make an object be eligible for collection, e.g. when that reference is the last remaining to the object.
You do NOT however, have to ALWAYS set a reference to null to make garbage collection "works". When variables goes out of scope, the reference is no longer alive, so in those kinds of cases explicitly setting to null is simply redundant code.
The classic example when explicitly setting to null DOES work is the Stack example: when the top element is popped from the Stack, the Stack should no longer refer to the object from its internal data structure.
See also
Effective Java 2nd Edition, Item 6: Eliminate obsolete object references
Related questions
Does variable = null set it for garbage collection
The answer is:
Define what you mean for an object reference to "exist".
It is impossible to know how many object references were even created, without details of the Point and Circle classes.
The answer is irrelevant, because after the main method exits none of the objects will be reachable ... whether or not the references still "exist".
We might infer that at the point in time immediately before the main method returns there will be one reachable reference to a Circle object and one reachable reference to a Point. But one has to make some (reasonable) assumptions about how those two classes are implemented to make that inference. (For example, one has to assume that the respective constructors don't add the Point and Circle reference to some static data structure.)
Are objects cleaned up when references to them are nulled?
No. Objects are cleaned up when the garbage collector runs, and it determines that the objects in question are no longer reachable. In this sense, "reachable" means that you can get to the object by following a chain of references to the object starting from:
a static attribute of some class
a local variable of some method that is currently being executed by some thread
an attribute of some other reachable object, or
an element of some other reachable array.
(I've simplified the explanations of GC and reachability a bit to avoid confusing the OP with things he/she won't understand yet.)
Related
I'm saving the previous value of a Java object. I (almost) understand references are strong, weak, etc. but I can't find an example that classifies my specific situation that is apparently referencing an out-of-scope object. (I've looked at a lot of posts on this subject.)
Is the Java reference aTestCopy to the out-of-scope array of objects aTest valid?
It's a shallow copy but is it subject to garbage collection thus I need a deep copy for it to work reliably every time? Or should the declaration of the new object aTest be placed outside the while with the "previous" copied object aTestCopy?
Is the use of a null a good practice for the first-time-through switch or should that be a separate boolean variable?
Thanks.
Tester[] aTestCopy = null;
while(true)
{
Tester[] aTest = myMethodReturnsATesterArray(); // new values
// need code to skip using aTestCopy the first time through - no previous value
// else use the previous value here
aTestCopy = aTest; // save them for the next use of previous values
}
There is no problem to use null as initial value for reference types in Java. But there isn't any relevance between initialize a reference type as null and garbage collection. You should initialize aTestCopy as null to use in another scope like in your case in while.
Garbage collection is triggered whenever an object in memory is not pointed anymore by any reference.
When you assign a reference type to another reference type (if it is not immutable in this case), you made copy the memory address of that value. So when you can make a change in aTestCopy will be reflected to the reference aTest.
In Java, variables do not hold objects, only references to objects.
The lifetime of objects is largely independent of the lifetime of variables: Objects are created by executing new, and reclaimed once the program has relinquished all means of accessing them (i.e. the object is no longer reachable form the references the program holds).
Put differently, the first variable to hold a reference to an object holds no special significance. In particular, it does not determine the lifetime of that object. Any reference will keep the object alive, and there can be no such thing as an "out of scope" object.
Similarly, when you assign a variable of reference type, you are only assigning the reference, causing both variables to point to the same object, and to see any changes done to this object though the other variable.
If you want a new object, you must use new (or call a method that uses new).
In your case, I'd make sure that myMethodReturnsATesterArray returns a new array, referencing new Tester objects. Then, the objects created by separate iterations of the loop will exist independently, allowing the loop to reference both the old and new objects and do whichever comparision it deems appropriate, without having to fear that the invocation of myMethodReturnsATesterArray has somehow changed the previous object.
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.
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.
In a multithreaded Android project, I'm seeing code like this:
final WeakReference<MyClass> myClassObjectWeakRef =
new WeakReference<MyClass>(aMyClassObject);
...then somewhere else:
if (myClassObjectWeakRef.get() != null) {
myClassObjectWeakRef.get().someMethod();
}
I'm pretty sure there is a possible race condition between the check and the use of the reference, if the last strong reference to the object is released between the two in another thread, but I can't find any documentation or anyone which/who can confirm this better than with a "you're probably right".
I would think the only right way to test & use a weak reference is done like this:
MyClass myObject = myClassObjectWeakRef.get();
// we now have a strong reference, or null: standard checks apply.
if (myObject != null) {
myObject.someMethod();
}
I'm very confident that the second method is 100% safe, but I wonder if there is some Java/compiler sugar/magic that I don't know about, which would make the first method safe.
So, is the first method 100% safe, or not?
The first method is definitely unsafe. Each call to get is independent. There is nothing preventing the GC from clearing the weakly reachable object after the first get and before the second.
The javadoc states
Suppose that the garbage collector determines at a certain point in
time that an object is weakly reachable. At that time it will
atomically clear all weak references to that object and all weak
references to any other weakly-reachable objects from which that
object is reachable through a chain of strong and soft references.
That can be at any point in time. Calling get(), which (potentially) pushes a reference to the object on the stack temporarily makes the object strongly reachable (it's on a thread's stack), but that reach-ability disappears the moment the comparison with null finishes. After that moment, the GC can determine that the object is weakly reachable and clear its reference. You'd then get a NullPointerException.
Use your second method. But note that by assigning it to a variable, you are making the referenced object strongly reachable.
Lets assume, there is a Tree object, with a root TreeNode object, and each TreeNode has leftNode and rightNode objects (e.g a BinaryTree object)
If i call:
myTree = null;
what really happens with the related TreeNode objects inside the tree? Will be garbage collected as well, or i have to set null all the related objects inside the tree object??
Garbage collection in Java is performed on the basis of "reachability". The JLS defines the term as follows:
"A reachable object is any object that can be accessed in any potential continuing computation from any live thread."
So long as an object is reachable1, it is not eligible for garbage collection.
The JLS leaves it up to the Java implementation to figure out how to determine whether an object could be accessible. If the implementation cannot be sure, it is free to treat a theoretically unreachable object as reachable ... and not collect it. (Indeed, the JLS allows an implementation to not collect anything, ever! No practical implementation would do that though2.)
In practice, (conservative) reachability is calculated by tracing; looking at what can be reached by following references starting with the class (static) variables, and local variables on thread stacks.
Here's what this means for your question:
If i call: myTree = null; what really happens with the related TreeNode objects inside the tree? Will be garbage collected as well, or i have to set null all the related objects inside the tree object??
Let's assume that myTree contains the last remaining reachable reference to the tree root.
Nothing happens immediately.
If the internal nodes were previously only reachable via the root node, then they are now unreachable, and eligible for garbage collection. (In this case, assigning null to references to internal nodes is unnecessary.)
However, if the internal nodes were reachable via other paths, they are presumably still reachable, and therefore NOT eligible for garbage collection. (In this case, assigning null to references to internal nodes is a mistake. You are dismantling a data structure that something else might later try to use.)
If myTree does not contain the last remaining reachable reference to the tree root, then nulling the internal reference is a mistake for the same reason as in 3. above.
So when should you null things to help the garbage collector?
The cases where you need to worry are when you can figure out that that the reference in some cell (local, instance or class variable, or array element) won't be used again, but the compiler and runtime can't! The cases fall into roughly three categories:
Object references in class variables ... which (by definition) never go out of scope.
Object references in local variables that are still in scope ... but won't be used. For example:
public List<Pig> pigSquadron(boolean pigsMightFly) {
List<Pig> airbornePigs = new ArrayList<Pig>();
while (...) {
Pig piggy = new Pig();
...
if (pigsMightFly) {
airbornePigs.add(piggy);
}
...
}
return airbornePigs.size() > 0 ? airbornePigs : null;
}
In the above, we know that if pigsMightFly is false, that the list object won't be used. But no mainstream Java compiler could be expected to figure this out.
Object references in instance variables or in array cells where the data structure invariants mean that they won't be used. #edalorzo's stack example is an example of this.
It should be noted that the compiler / runtime can sometimes figure out that an in-scope variable is effectively dead. For example:
public void method(...) {
Object o = ...
Object p = ...
while (...) {
// Do things to 'o' and 'p'
}
// No further references to 'o'
// Do lots more things to 'p'
}
Some Java compilers / runtimes may be able to detect that 'o' is not needed after the loop ends, and treat the variable as dead.
1 - In fact, what we are talking about here is strong reachability. The GC reachability model is more complicated when you consider soft, weak and phantom references. However, these are not relevant to the OP's use-case.
2 - In Java 11 there is an experimental GC called the Epsilon GC that explicitly doesn't collect anything.
They will be garbage collected unless you have other references to them (probably manual). If you just have a reference to the tree, then yes, they will be garbage collected.
You can't set an object to null, only a variable which might contain an pointer/reference to this object. The object itself is not affected by this. But if now no paths from any living thread (i.e. local variable of any running method) to your object exist, it will be garbage-collected, if and when the memory is needed. This applies to any objects, also the ones which are referred to from your original tree object.
Note that for local variables you normally not have to set them to null if the method (or block) will finish soon anyway.
myTree is just a reference variable that previously pointed to an object in the heap. Now you are setting that to null. If you don't have any other reference to that object, then that object will be eligible for garbage collection.
To let the garbage collector remove the object myTree just make a call to gc() after you've set it to null
myTree=null;
System.gc();
Note that the object is removed only when there is no other reference pointing to it.
In Java, you do not need to explicitly set objects to null to allow them to be GC'd. Objects are eligible for GC when there are no references to it (ignoring the java.lang.ref.* classes).
An object gets collected when there are no more references to it.
In your case, the nodes referred to directly by the object formally referenced by myTree (the root node) will be collected, and so on.
This of course is not the case if you have outstanding references to nodes outside of the tree. Those will get GC'd once those references go out of scope (along with anything only they refer to)