Does GC help hide local variables in Java?

I was forced to add an instruction myLocalVar = null; in the finally clause just before leaving the method. The reason is to help the GC. They told me that I will receive SMS during the night the next time the server crashes, so I better do this :-).

I think this is pointless since myLocalVar is bound to a method and will be "lost" as soon as the method exits. Extra zeroing just pollutes the code, but is harmless.

My question is: where does this myth about helping GC come from? (I was mentioned in the "Java Memory Books"). Do you know any article from the "authorities" that explains this in more detail? Is it possible that this is not a myth, but really helps? If so, how? Can damage to local variables do any harm?

To clarify, the method is as follows:

 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 } } 
+40
java variables garbage-collection null local
Jan 23 '09 at 17:01
source share
15 answers

There was an old piece of Sun documentation, The performance of the Java platform (the link, unfortunately, is now broken, and I could not find a new one), which describes a situation in which resetting a local variable that fell out of scope actually affected the GC.

However, the document mentioned a very old version of java. As mentioned in this question (which also contains the limit of the problem described in the document), this no longer affects current JVM implementations.

+28
Feb 02 '09 at 16:00
source share

The Java GC is supposed to be “sound,” but not necessarily immediately “complete.” In other words, it is designed so that it never deletes objects that are still accessible in at least one path (and therefore cause the link to freeze). It is not necessarily completed right away, as it may take a while until it removes everything that can be removed.

I think most GC myths come from a misunderstanding of this concept. Many people contain too many instance variables , and this causes problems, but this, of course, is not a problem.

Other people put local variables in an instance variable (for example, passing it to a function), and then believe that resetting the local variable somehow excludes this variable, which, of course, is wrong.

Finally, there are people who rely excessively on the GC and believe that a functional shutdown will be performed for them (for example, close connections when a variable is deleted), which, of course, is not so. I think the source of this line is "I really really managed it, but I'm not sure how to provide it."

So, you are right that it does not matter.

+19
Jan 23 '09 at 17:08
source share

Not in this case. myLocalVar goes out of scope immediately after the function returns, so setting a reference to null does absolutely nothing.

+9
Jan 23 '09 at 17:06
source share

This is a myth that goes back to when Java first came out, and the C ++ guys did not trust gc.

gc knows what he is doing. zeroing var wont will hurt anything, but it won't help anything either. This time, Jeff had a pretty funny post .

+8
Jan 23 '09 at 17:05
source share

As far as I know, null entering a variable just before it leaves the scope has nothing to do with the garbage collector.

Of course there are cases where it really helps. For example. when var not a local variable, but a member or a static member. Then the destruction of the link can make the object inaccessible and, therefore, have the right to collect.

Another case where it can help even with local variables, if the function allocates a lot of temporary memory to initialize some data for further processing and can discard all references to temporary memory before processing starts:

 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(); } 
+5
Jan 23 '09 at 17:10
source share

You're right. To discard a variable that will immediately fall out of scope is not necessary in any case and has no meaning for the GC. All he does is clutter up the code. In Effective Java 2nd Edition, the author recommends abandoning unnecessary zeroing of local variables. See Effective Java, 2nd Edition, Item 6: Eliminate obsolete object references for a complete record.

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

When a local variable goes out of scope, it is exactly the same as if you hadn’t referenced it.

EDIT: Add a link to Effective Java 2nd Edition on the Sun website.

+3
Jan 23 '09 at 18:00
source share

Zero local variables can really help in some cases with an edge. This does not apply to the situation in the original question, but in any case is educational ... 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; commented out, the object in the local variable cannot be garbage collected during the while loop. The reason is that the Java Virtual Machine is not aware of such areas. All that he has:

 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 */ } 

Information about the scope of the local variable is missing. Therefore, from the perspective of the JVM above, the program is equivalent:

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

(generated by JAD decompiler)

Conclusion: There are some reasons for resetting local variables in special cases like this. But if the method ends soon (as in my original question), this will not help.

This was inspired by a comment by Zdenek Tronicek on the java-cz mailing list (in Czech, sorry)

+3
Feb 24 '09 at 20:16
source share

As you rightly point out, zeroing is completely pointless in this case.

Back to JDK1.3 I really had a case with an extremely large graph of objects, which also contained many circular links inside the graph. Removing some of the links did noticeably improve GC time.

I'm not sure if this applies to a modern virtual machine. Garbage collectors are becoming more intelligent.

+2
Jan 23 '09 at 17:07
source share

Another possible factor in this myth is that it can change the null value for a local variable if you are finished with it before the end of the method. This will allow the GC to collect this object before the method completes, which may be useful.

Someone may have been given this advice at some point and he misunderstood it as the need to always exclude local variables.

+1
Jan 23 '09 at 18:49
source share

There are only two cases where I found that setting a variable to null was useful:

  • In unit tests that create a large object in a field. The module tester can save the test object and objects created for all tests. This can lead to the tester running out of memory. In this case, it is often better to use local variables instead of fields, but if a field is required, it can be cleared in tearDown.
  • Circular links can be cleared by the GC, but not with a simple incremental collection. This may mean that objects with circular links take more work to clear and can live much longer than otherwise. This usually doesn’t matter, but if you are trying to shorten the time for a full GC, it can help break the circular links.
+1
Jan 23 '09 at 21:19
source share

I don’t know the technical details, but, as far as I remember, a variable is nothing more than a link from the current frame of the stack, and until this link is deleted, the object cannot be garbage collected. Now, but by explicitly setting it to null, you are convinced that the link is gone. If you do not, you basically allow the virtual machine to decide when this link will be cleared, which may or may not be when leaving the area (unlike C ++, if the object is on the stack and MUST be destroyed). Perhaps when the stop frame will be overwritten as follows. I'm not sure if there is a virtual machine that does this.

The short answer, although this is not necessary, the brand and the scan will ultimately receive it. This is nothing more than a matter of time.

0
Jan 23 '09 at 17:12
source share

In some cases, it is useful to use null variables (usually instance or class variables). But resetting a local variable just before the end of the method does nothing.

When you set the variable to null , you simply delete this reference to the actual object. But when a local variable goes out of scope, the link is deleted anyway; therefore, setting it to zero, since the last line of the method is simply redundant.

0
Jan 23 '09 at 17:14
source share

If your class has been hanging for a long time, then zeroing the objects referenced by the links will allow them to be collected.

This is almost never a problem, most often zeroing objects is not useful.

When you think about allocating and freeing an object, pay attention to what the “System” means: Active threads, windows that have not been disposed of () d, and one or two more things, but I can’t remember right now .

Each object in your system "hangs" on these mount points in a giant inverted tree. If you cut any branch that is free of these “roots,” the whole branch falls to the ground and is collected by a lawn mower to collect garbage.

Most classes need all of their member variables throughout their entire life cycle — and when their life is over, their entire branch is truncated, including all their members; therefore, null is not necessary.

(these trims, by the way, are quite effective, even more than C ++ for free, because they do not require touching each object as it is released)

0
Jan 23 '09 at 17:32
source share

If you no longer need large objects in the local area, 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 this does not make sense before returning, because it is executed by the JVM automatically. Therefore, I agree with all posts before.

0
Apr 04 '09 at 2:39
source share

Not only resetting the local variable, as this is pointless from the point of view of the GC, it can lead to unnecessary loading of the variable in the register to exclude it, which makes the situation worse. Imagine if there are 1000 lines of code between the last read or write in myLocalVar and then you reference it to exclude the link. The value is long gone from the register, but you need to load it back into memory to work with it.

0
Apr 6 '09 at 14:43
source share



All Articles