views:

1556

answers:

15

I was 'forced' to add myLocalVar = null; statement into finally clause just before leaving method. Reason is to help GC. I was told I will get SMS's during night when server crashes next time, so I better did it :-).

I think this is pointless, as myLocalVar is scoped to method, and will be 'lost' as soon as method exits. Extra nulling just pollutes the code, but is harmless otherwise.

My question is, where does this myth about helping GC come from? (I was referred to "Java memory books") Do you know any article from 'authorities' which explain it in more depth? Is there possibility this is not a myth, but really helps somehow? If so, how? May nulling local variables cause any harm?

To clarify, method look like this:

void method() {
  MyClass myLocalVar = null;
  try {
    myLocalVar = get reference to object;
    ... do more here ...
  } finally {
    if (myLocalVar != null) {
      myLocalVar.close(); // it is resource which we should close
    }

    myLocalVar = null; // THIS IS THE LINE I AM TALKING ABOUT
  }
}
+5  A: 

That is a myth that goes way back to when java first came out and C++ guys didn't trust the gc.

The gc knows what it is doing. nulling out var wont hurt anything, but it wont really help anything either. Jeff had a pretty funny post on this just the other day.

Matt Briggs
Great title "Die, You Gravy Sucking Pig Dog!" :-) Thanks for pointing this out.
Peter Štibraný
Some of that post is fine. Other parts are dangerous. Regarding calling Dispose as an "optimisation" is harmful, IMO. Read the comments.
Jon Skeet
It is not very clearly written either. Some people are actually taking the message home that they really should close, dispose and null resources. Example: http://stackoverflow.com/questions/452327/proper-way-to-stop-listening-on-a-socket#452348
Wim Coenen
-1 from me because I don't think that blog post is 'great' at all.
Outlaw Programmer
edited from "great" to "pretty funny", because that was why I thought it was great in the first place. Jon is right about the IDisposable thing
Matt Briggs
+8  A: 

Not in this case. myLocalVar falls out of scope as soon as the function returns, so setting the reference to null does absolutely nothing.

Outlaw Programmer
+2  A: 

As you correctly point out, nulling out in this case is totally pointless.

Back on JDK1.3 I did actually have a case with an extremely large object graph that also contained lots of circular references within the graph. Clearing out a few of the references did actually improve GC times quite noticeably.

I am not sure if this would apply with a modern VM. Garbage collectors have become increasingly smarter.

krosenvold
For a garbage collector that uses reference counting, it's possible to get a memory leak with 2 objects that (circularly) reference each other, as each still has an existing reference, and the GC wouldn't realize that those references themselves were to GCable objects. The modern JVM doesn't do this
Steve B.
Old JMVs didn't do that either.
Tom Hawtin - tackline
I don't know why I had improvements but I suppose it really meant less work for the garbage collector. I am not claiming any memory leak, just improved GC times.
krosenvold
If you have a large object graph and you release objects from that graph, explicitly nulling the references to the objects being released allows GC to reclaim the items, and it causes there to be fewer "live" objects. Both may help speed GC.
Eddie
I also had such a situation. In my case it was a very long chain of objects. A linked list that grew from the tail, and shrank from the head. Very quickly. One GC couldn't keep up until until we nulled the links coming off of the head. This was Java 1.3
Darron
+13  A: 

The Java GC is supposed to be "sound" but is not necessarily immediately "complete". In other words, it is designed so that it would never eliminate objects that are still accessible by at least one path (and thus cause a dangling reference). It is not necessarily immediately complete since it might take time until it removes everything that can be removed.

I think that most GC myths come from a misunderstanding of that concept. Many people keep too many instance variables alive, and that causes problems, but that is of course not the issue here.

Other people put the local variables in an instance variable (e.g., by passing it to function), and then think that nullifying the local variable somehow eliminates the variable, which is of course untrue.

Finally, there are people who overrely on the GC and think it would do functional shutdown for them (E.g., close connections when variable is removed) which is of course not the case. I think the source of this line is the "I'm really really done with it but I'm not sure how to ensure that".

So yeah, you're correct that it's unneccessary.

Uri
+3  A: 

To the best of my knowledge, nulling a variable immediately before it leaves the scope makes no difference to the garbage collector.

Of course there are cases where it indeed does help. E.g. when var is not a local variable but a member or static member. Then destroying the reference might make the object unreachable and thus eligible for collection.

Another case where it might help even with local variables if a function allocates much temporary memory to initialise some data for further processing and can throw away all references to the temporary memory before beginning the processing:

SomeResult SomeFunction(SomeClass param) {
    TempData big = new TempData(param);
    IntermediateResult intermediate = big.GetIntermediateResult();
    big = null; // allow GC to reclaim the memory before returning from the function
    intermediate.FurtherProcessing();
    return intermediate.EvenMoreProcessing();
}
David Schmitt
A: 

I don't know the technical details, but as far as I can remember, the variable is nothing more than reference from the current stack frame, and until this reference is removed, the object cannot be garbage collected. Now, but explicitly setting it to null, you've made sure that the reference is gone. If you don't you're basically letting the VM decide when this reference is cleared, which might or might not be upon exiting the scope (unlike C++, if the object is located on the stack and MUST be destroyed). It might be when the stack frame is overwritten with the next. I'm not sure if there's actually a VM which does this.

Short answer though, it's unnecessary, the mark and sweep will get it eventually. It's at most a question of time.

roe
I believe that even if stack was not overwritten, it would still not count as reference to object, as this part of stack is unused.
Peter Štibraný
theoretically you're of course correct, how it's actually implemented is a different story.
roe
The object is on the heap but the reference to it is on the stack. As soon as the function returns, the reference gets popped off and the object no longer has any valid references. It's free to be GCed any time thereafter. No need to "make sure" the reference is gone, it's ALWAYS gone here.
Outlaw Programmer
I never said there's a need to make sure, the question was whether it made a difference, and I said it's up to how the VM implementation handles references from stack frames. It might not (although it certainly is the most appealing) clear it when you leave the scope.
roe
Per the JLS and JVMSpec, a VM doesn't even have to garbage-collect ... but they do. And while it's possible that some implementation will look at every possible location in memory (even unused) and decide it might point to an object, that makes no sense whatsoever.
kdgregory
I don't know how early JVMs implemented this, but in any recent JVM, a variable going out of scope immediately makes its referenced object eligible for garbage collection if there is no other reference to it.
Eddie
A: 

In some circumstances, it can be useful to null variables (usually instance or class variables). But nulling a local variable immediately before the end of the method does absolutely nothing.

When you set a variable to null, you are merely removing that reference to the actual object. But when a local variable goes out of scope, the reference is removed anyway; therefore, setting it to null as the last line of the method is simply redundant.

Michael Myers
A: 

If your class hangs around for a long time, then nulling out objects it references will allow them to be collected.

This is almost never an issue, most times nulling objects is not useful.

When you think of object allocation and freeing, pay attention to the things that the "System" has handles to: Active threads, windows that haven't been dispose()d, and one or two more things but I can't remember right now.

Every object in your system "Hangs" off these mount points in a giant upside-down tree. If you cut any branch free from these "Roots" the entire branch falls to the ground and is collected by the Lawn Mower of Garbage Collecting.

Most classes need all their member variables for their entire lifecycle--and when their life is finished, their entire branch is trimmed including all their members; hence--no need to null.

(these trims, by the way, are quite efficient, even more than C++'s free since they don't require touching each object as it's freed)

Bill K
+2  A: 

You are correct. Nulling out a variable that will immediately fall out of scope anyway is unnecessary and makes no difference whatsoever to GC. All it does is clutter the code. In Effective Java 2nd Edition, the author recommends against unnecessary nulling out of local variables. See Effective Java, 2nd Edition, Item 6: Eliminate obsolete object references, for a full writeup.

You can also see this in the article Creating and Destroying Java Objects, at InformIT. Read the entire article to find the place where Joshua Bloch agrees with you.

When a local variable falls out of scope, it is exactly the same as if you null the reference to it.

EDIT: Add link to Effective Java 2nd Edition at Sun website

Eddie
Thank you for links, esp. informit excerpts from EJ 2nd ed.
Peter Štibraný
+1  A: 

Another possible factor in this myth is that it can make a difference to null out a local variable if you are done with it before the end of the method. This would allow the GC to collect that object before the method is complete, which could be useful.

Someone might have been given that advice at some point and misunderstood it as a need to always null out the local variables.

Dave Costa
A: 

There are only two cases where I have found setting a variable to null has been useful:

  • In unit tests which create a large object in a field. The unit tester may retain the test object and the objects you created for the life of all the tests. This can cause the tester to run out of memory. In this case it is often better to use local variables instead of fields, but if a field required it can be cleared in the tearDown.
  • Circular references can be cleaned up by the GC but not with a simple incremental collection. This can mean that objects with circular references take more work to clear and can live much long than they would otherwise. Generally this doesn't matter but if you are trying to reduce your full GC time, it can help to break circular references.
Peter Lawrey
+15  A: 

Java Platform Performance describes a situation where nulling a local variable which dropped out of scope actually had an effect on the GC.

However, the paper refers to a very old version of java. As mentioned in this question, this no longer affects current JVM implementations.

Bill Michell
Thanks! This explains where does this myth originate from.
Peter Štibraný
So? what was the answer?... ( don't make me read ) :P
OscarRyz
In my original question, it doesn't help. But see also my answer below (http://stackoverflow.com/questions/473685#583387), there is indeed case where it can help.
Peter Štibraný
+3  A: 

Nulling local variables can indeed help in some edge cases. This doesn't apply to situation in original question, but is educational anyway... Let's consider this program:

public class Main {
    public static void main(String[] args) {
       {
           Main local = new Main();

           // inner = null;
       }

       while (true) {
           // long running method
       }
    }
}

If inner = null; is commented out, object in local variable cannot be garbage-collected during while loop. Reason is that Java Virtual Machine doesn't know about scopes like this. All it has is:

D:\workspaces\workspace-3.4\test\src>javap -verbose -c Main
public class Main extends java.lang.Object
  minor version: 0
  major version: 50
  Constant pool:
const #1 = Method       #4.#11; //  java/lang/Object."<init>":()V
const #2 = class        #12;    //  Main
const #3 = Method       #2.#11; //  Main."<init>":()V
const #4 = class        #13;    //  java/lang/Object
const #5 = Asciz        <init>;
const #6 = Asciz        ()V;
const #7 = Asciz        Code;
const #8 = Asciz        main;
const #9 = Asciz        ([Ljava/lang/String;)V;
const #10 = Asciz       StackMapTable;
const #11 = NameAndType #5:#6;//  "<init>":()V
const #12 = Asciz       Main;
const #13 = Asciz       java/lang/Object;

{
public Main();
  Code:
   Stack=1, Locals=1, Args_size=1
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

public static void main(java.lang.String[]);
  Code:
   Stack=2, Locals=2, Args_size=1
   0:   new     #2; //class Main
   3:   dup
   4:   invokespecial   #3; //Method "<init>":()V
   7:   astore_1
   8:   goto    8
  StackMapTable: number_of_entries = 1
   frame_type = 8 /* same */

}

There is no information about scope of local variable. So from JVM's point of view, above program is equivalent to:

public class Main
{

    public Main() { }

    public static void main(String args[])
    {
        Main main1 = new Main();
        do
            ;
        while(true);
    }
}

(Generated by JAD decompiler)

Conclusion: there IS some rationale in nulling local variables in very special cases like this. But if method is going to finish soon (like in my original question), it doesn't help.

This was inspired by comment from Zdenek Tronicek on java-cz mailing list (in czech language, sorry)

Peter Štibraný
On the other hand, JVM can probably detect that local variable is not used after instruction 7, and optimize it away.
Peter Štibraný
Which compiler/JVM did you use for this? See http://stackoverflow.com/questions/271613/are-invisible-references-still-a-problem-in-recent-jvms for experimental evidence that recent JVMs can garbage collect such inner-scope variables after they drop out of scope.
Bill Michell
I used java 1.6.0_12 from Sun. Thanks for pointing out that q/a. I see that it's the same as I already accepted for this question ;-) (your answer ... shame on me, I should have read it more thoroughly for the first time)
Peter Štibraný
A: 

If you don't need large objects in your local scope anymore, you can give the JVM a hint and set the reference NULL.

public void foobar()
{
    List<SomeObject> dataList = new ArrayList<SomeObject>();

    // heavy computation here where objects are added to dataList 
    // and the list grows, maybe you will sort the list and
    // you just need the first element... 

    SomeObject smallest = dataList.get(0);

    // more heavy computation will follow, where dataList is never used again
    // so give the JVM a hint to drop it on its on discretion
    dataList = null;

    // ok, do your stuff other heavy stuff here... maybe you even need the 
    // memory that was occupied by dataList before... 

    // end of game and the JVM will take care of everything, no hints needed
}

But it does not make sense before the return, because this is done by the JVM automatically. So I agree with all postings before.

ReneS
A: 

Not only is nulling a local variable like that meaningless in terms of GC, it may cause unnecessary loading of the variable into a register in order to null it out, which makes the situation worse. Imagine if there is 1000 lines of code between the last read or write to myLocalVar, and then you reference it just to null out the reference. The value is long gone from the register, but you have to load it back in to memory to work with it.

Kai