Garbage Collector in Java - Set an Object Null

Garbage collector in java - set an object null

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.

  1. Nothing happens immediately.
  2. 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.)
  3. 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:

  1. Object references in class variables ... which (by definition) never go out of scope.
  2. 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.

  3. 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.

Does assigning objects to null in Java impact garbage collection?

Typically, no.

But like all things: it depends. The GC in Java these days is VERY good and everything should be cleaned up very shortly after it is no longer reachable. This is just after leaving a method for local variables, and when a class instance is no longer referenced for fields.

You only need to explicitly null if you know it would remain referenced otherwise. For example an array which is kept around. You may want to null the individual elements of the array when they are no longer needed.

For example, this code from ArrayList:

public E remove(int index) {
RangeCheck(index);

modCount++;
E oldValue = (E) elementData[index];

int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // Let gc do its work

return oldValue;
}

Also, explicitly nulling an object will not cause an object to be collected any sooner than if it just went out of scope naturally as long as no references remain.

Both:

void foo() {
Object o = new Object();
/// do stuff with o
}

and:

void foo() {
Object o = new Object();
/// do stuff with o
o = null;
}

Are functionally equivalent.

Is everything null in Java eligible for garbage collection?

There is no "null object", and null is the closest thing that exists to an empty reference. The key definitions are in the Java Language Specification, 4.3.1. Objects:

An object is a class instance or an array.

The reference values (often just references) are pointers to these
objects, and a special null reference, which refers to no object.

obj1 = null; changes the reference variable obj1 to be null. If it previously referred to an object it no longer does so.

There may be other references that refer to that object, so that the object remains reachable, and the garbage collector will leave it alone. If obj1 was the last reference to the object, it is no longer reachable, and is eligible for finalization.

Does variable = null set it for garbage collection

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

Does setting Java objects to null do anything anymore?

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.

java garbage collection and null reference

c3 is a local handle with a null reference, it does not point (and hever has pointed) to an allocated object. Therefore there's nothing to GC.

Garbage collector in java - set an object null

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.

  1. Nothing happens immediately.
  2. 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.)
  3. 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:

  1. Object references in class variables ... which (by definition) never go out of scope.
  2. 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.

  3. 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.

When to explicitly set objects to null in order to make the memory reclaimable in Java?

Pretty much everything other than primitives and Strings are instantiated with a new. And you should not be worried about Garbage collection to the extent that you have to set variables to null to make them eligible. GC has become very intelligent in last few years that we don't have to resort these tricks. e.g. Any orphaned object in heap ( which is not referred by anything) is a GC candidate. If you have your code structured, all method scope objects are GC candidate once the method has finished execution, same with a state variable as soon as the object of the class itself is dereferenced.

clearing or set null to objects in java

Firstly, you never set an object to null. That concept has no meaning. You can assign a value of null to a variable, but you need to distinguish between the concepts of "variable" and "object" very carefully. Once you do, your question will sort of answer itself :)

Now in terms of "shallow copy" vs "deep copy" - it's probably worth avoiding the term "shallow copy" here, as usually a shallow copy involves creating a new object, but just copying the fields of an existing object directly. A deep copy would take a copy of the objects referred to by those fields as well (for reference type fields). A simple assignment like this:

ArrayList<String> list1 = new ArrayList<String>();
ArrayList<String> list2 = list1;

... doesn't do either a shallow copy or a deep copy in that sense. It just copies the reference. After the code above, list1 and list2 are independent variables - they just happen to have the same values (references) at the moment. We could change the value of one of them, and it wouldn't affect the other:

list1 = null;
System.out.println(list2.size()); // Just prints 0

Now if instead of changing the variables, we make a change to the object that the variables' values refer to, that change will be visible via the other variable too:

list2.add("Foo");
System.out.println(list1.get(0)); // Prints Foo

So back to your original question - you never store actual objects in a map, list, array etc. You only ever store references. An object can only be garbage collected when there are no ways of "live" code reaching that object any more. So in this case:

List<String> list = new ArrayList<String>();
Map<String, List<String>> map = new HashMap<String, List<String>>();
map.put("Foo", list);
list = null;

... the ArrayList object still can't be garbage collected, because the Map has an entry which refers to it.



Related Topics



Leave a reply



Submit