In Java, what is an unreachable object? When does the object become unreachable? While studying garbage collection I was not able to understand this concept.
Can anyone give any ideas with examples?
When there are no longer any reference variables referring to it, OR when it is orphaned in an island.
An island being an object that has a reference variable pointing to it, however that object has no reference variables pointing to it.
class A { int i = 5; }
class B { A a = new A(); }
class C {
B b;
public static void main(String args[]) {
C c = new C();
c.b = new B();
// instance of A, B, and C created
c.b = null;
// instance of B and A eligible to be garbage collected.
}
EDIT: Just want to point out that even though the instance of A has a reference, it is on an island now because the instance of B does not have a reference to it. The A instance is eligible for garbage collection.
An object is unrechable when there are no more references to it, or those references are themselves from unrechable objects.
Integer i = new Integer(4);
// the new Integer object is reachable via the reference in 'i'
i = null;
// the Integer object is no longer reachable.
in the object graph when one is not linked to it, then the reference become unreachable. then then the garbage collector scans for these dangling orphan objects and swipe out regaining allocated memory.
java.lang.ref.{Phantom,Soft,Weak} Reference Enqueues unreachable objects.
If the finalizer is run, the GC already knows its unreachable.
read about finalization- http://java.sun.com/developer/technicalArticles/javase/finalization/
In a language which has only strong references, heap objects can either be reachable or unreachable from the
program. The set of reachable objects is determined by the set of class variables and method variables in the program
pointing to heap objects. This set is usually referred to as the root set of the program. An object pointed by a variable
in the root set of the program is reachable. In addition, an object might be indirectly reachable. That is, an object is
reachable if there is another reachable object pointing to it. Such chain of references from the root set of the program
to a heap object is called reachability path. An object may have more than one reachability path to it as well as have
no reachability paths at all. If the object has no reachability paths it is deemed garbage and can be immediately
collected by the garbage collector.
An object enters an unreachable state when no more strong references to it exist. When an object is unreachable, it is a candidate for collection. Note the wording: Just because an object is a candidate for collection doesn't mean it will be immediately collected. The JVM is free to delay collection until there is an immediate need for the memory being consumed by the object.
It's important to note that not just any strong reference will hold an object in memory. These must be references that chain from a garbage collection root. GC roots are a special class of variable that includes
Temporary variables on the stack (of any thread)
Static variables (from any class)
Special references from JNI native code
more if you like to http://java.sun.com/docs/books/performance/1st_edition/html/JPAppGC.fm.html
An unreachable object, is an object that doesn't have a "reachable" reference to it.
In other words, no references to it.
Related
I'm confused with this program:
class Point {
private final int x;
private final int y;
}
public class App
{
WeakReference<Point> newPoint() {
Point referent = new Point();
return new WeakReference<Point>(referent); // after return, stack parameter referent is invalid.
}
public static void main( String[] args ) {
App a = new App();
WeakReference<Point> wp = a.newPoint(); // wp is hold valid or invalid reference?
System.out.println(wp.get()); // not null
}
}
I knew that if weak reference is pointing to an object that's no longer alive, its get() should return null. But in my code, seems its still alive.
Where did I get wrong?
I knew that if weak reference is pointing to an object that's no longer alive, its get() should return null. But in my code, seems its still alive.
Your understanding is imprecise, especially where it relies on the idea of aliveness. Reference objects in general and WeakReference objects in particular are not directly concerned with any of the senses of aliveness that I recognize. Rather, they are concerned with reachability.
The API docs for java.lang.Reference#get() (which is not overridden by WeakReference) say this:
Returns this reference object's referent. If this reference object has been cleared, either by the program or by the garbage collector, then this method returns null.
Note well that the condition for get() returning null is rather specific: the reference object has been cleared. This is achieved for a given instance by invoking that instance's clear() method. As the doc indicates, this may be done by the garbage collector or by the application.
Among the key differences between Reference subclasses is the conditions under which the garbage collector will perform such clearing. For WeakReferences, the API docs say:
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 [...].
Thus, until the garbage collector determines that a given object is (only) weakly reachable, it will not clear weak references to that object. The garbage collector probably does not run at all during the brief run of your small program, and if it did run, it would be surprising for it to be timed correctly to observe the Point in question to be weakly reachable before the reference's get() method is invoked.
You could try forcing a GC run by invoking System.gc() at the appropriate place. I anticipate that doing so will result in the weak reference being cleared. That would be for demonstrative purposes only, however. Generally speaking, you should rely on Java to perform GC when appropriate, not force it.
Suppose we have a class:
public class test{
public String member;
public test()
{
member = new String("internal object");
}
};
If I wrote this :
String refToUnreferencedClassMember = new test().member;
Is this problematic? The unreferenced object new test() has no reference pointing to itself, but there is a reference pointing to it's member object String member. If the unreferenced object is garbage collected, then refToUnreferencedClassMember will be invalid.
Thanks for your help. I don't know whether garbage collection will take place in this situation.
In this particular case,
new test().member;
will point to a String object in java heapspace.
Now when you assign it to
refToUnreferencedClassMember
then that String object would have two references i.e. one via anonymous new test() object and another via refToUnreferencedClassMember.
Note that test object would be eligible for GC. And when the anonymous new test() object is GC'd, your string object would still have one reference left i.e. refToUnreferencedClassMember, thus not allowing it to be GC'd.
Is this problematic?
No.
The unreferenced object new test() has no reference pointing to itself, but there is a reference pointing to its member object String member.
Correct.
If the unreferenced object is garbage collected, then refToUnreferencedClassMember will be invalid.
No it won't, unless it is unreferenced. As it is referenced in your example, the problem disappears.
That field has no knowledge regarding that enclosing object.
Therefore that enclosing object is immediately eligible to be garbage collected.
That string stays until the reference to it goes away.
But please note: from the object oriented point of view, you really want to avoid exposing mutable fields of classes. Allowing other classes to manipulate the internal state of members is something to not do!
This question arises when I am learning the LinkedList data structure. Assume every Link (or Node) is represented by an object which contains two fields, data & next points to the next link. If I want to delete a specific node, clearly I will update the previous Link's next field. But should I set deleted link's next field to null, so as to make sure it will be reclaimed by the garbage collector ?
If my description is not clear, I try to generalize (or simplify) my question. Suppose an object a1 of class A which has a field, which references another object a2 of the same class. If there is no reference to object a1, will it be eligible for garbage collector ? Or we must explicitly set reference field in a1 to be null ? (don't care about object a2, there are other references to it besides the reference field in a1).
Garbage collector ideally collect all objects, which are not reachable by program flow. Even if this object has references to everything in JVM.
Object becomes unreachable if all running threads of program don't contain any direct or indirect references to it.
Direct reference looks like this:
void main(String... args){
Object a = new Object(); // <- from here main thread of program
// has reference to object `a`
...
}
Indirect reference looks like this:
void main(String... args){
List b = new ArrayList();
b.add(new Object()); // <- here you can't access object by typing `a`
// as in previous example, but you can get access with `b.get(0);`
// so that object can be accessed indirectly -> it is reachable.
}
It also handles properly cases of big isles of objects, which have references to each other, but none of which is reachable from program flow anymore.
MyClass a = new MyClass();
MyClass b = new MyClass();
a.field = b;
b.field = a;
// at this point a and b are reachable so they cannot be collected
b = null;
// at this point b's object is reachable indirectly through `a.field`
// so neither a nor b can be collected
a = null;
// at this point you cannot reach neither a nor b
// so a and b can be garbage collected,
// despite the fact that a is referenced by b and vice versa
UPD: added examples, changed some words to make answer clearer.
Your object a1 can be collected even if its fields still reference other objects. You do not need to set its fields to null.
The garbage collector collects objects which are not reachable. An object can hold references to others and still be collected. An object may have references to it, from other non-reachable objects, and still be collected.
All orphan objects are automatically eligible for garbage collection. And you do not need to explicitility set reference to null (however it's a good coding practice).
When the garbage collector will run, it will see that now a1 needs to be garbage collected as there are no longer references to it.
Also it will remove the reference field in a1 pointing to object of a2
but still for a2 (as you have mentioned for a2 there are other references to it besides the reference field in a1) so it is not eligible for garbage collection, hence it remains.
If I have code similar to the following:
public Constructor(final Object o) {
taskSystem.add(new CycleTask(15, 15, -1) {
#Override
public void execute() throws Throwable {
//access o here every 15 cycles forever
}
});
}
When would o be garbage collected, if ever? Only when the task has been collected, or will it remain in memory forever because it's final?
o might get garbage collected once it is not reachable any longer, whether it is final or not. Obviously, as long as execute is running, if it needs to access o, it will prevent GC.
When execute is done running, and assuming you have not stored any references to o (for example in a collection), it will be flagged as ready for garbage collection.
When the anonymous class instance becomes eligible for garbage collection, if nothing else refers to the object that o referred to when the method was called, that object will become eligible for garbage collection.
There's nothing special about final variables which deters garbage collection.
'final' has no effect on GC. The object will become eligible for collection when it becomes unreachable. In this case there are at least three references, any one of which can stop that: the 'final' parameter, which disappears when the method returns; the caller's reference; and the copy of the final variable in the anonymous class instance.
There is no relationship between final keyword and the lifetime of the variable.
It will be garbage collected when not needed anymore, and since it's a parameter this can happen just outside the method (if there is no reference outside).
The final keyword is just a constraint given to the compiler to forbid any further modification of the reference o after the call of the function.
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)