Running on Java 24-ea+28-3562 (Preview)
Home of The JavaSpecialists' Newsletter

060Nulling Variables and Garbage Collection

Author: Jack ShiraziDate: 2002-11-29Java Version: 1.4Category: Performance
 

Abstract: For years, programmers have spread the misinformation that it was necessary to set local variables to null to avoid memory leaks. Fortunately Java is smart enough to do that without our help.

 

Welcome to the 60th edition of The Java(tm) Specialists' Newsletter sent to 5150 Java Specialists in 91 countries. Thank you so much for your support this year, writing this newsletter, and especially reading your replies, has been an absolute pleasure. One thing that excites me is seeing famous names pop up on my reader list. One of these, Jack Shirazi, a household name in Java performance circles and author of Java Performance Tuning [ISBN 0596000154] , has been watching our newsletter for about a year and Jack and I have often had interesting discussions about the finer details of Java performance. This month Jack decided to interview me, you can read the interview on his website if you would like to.

Today Jack sent me an article for our newsletter, and I am honoured to publish it. Thanks Jack for this excellent article, we all really appreciate the time and effort you took in writing it for us.

After mentioning in my last newsletter how fantastic South Africa is, I have seen a dramatic strengthening of our currency. Ours is the best performing currency against the US$ in the last 12 months. I have come to the conclusion that someone on my mailing list has so much money that they can influence the economy of our country ;-)

Enough of my musing, over to Jack Shirazi:

javaspecialists.teachable.com: Please visit our new self-study course catalog to see how you can upskill your Java knowledge.

Nulling Variables and Garbage Collection

At JavaPerformanceTuning.com, we have a monthly newsletter which includes a roundup of recent performance related discussions from various discussion groups. (We also have many more columns, covering almost all recent Java performance related activity, including interviews - last month we interviewed none other than our excellent host, Heinz). The discussions we report are quite interesting, and sometimes a really fascinating one pops up.

One such discussion at Javagaming.org considered whether setting variables to null helps garbage collection in any significant way. After a little inconclusive discussion, a Sun engineer jumped in with a really interesting example (Javagaming.org is a Sun owned discussion board, run by a couple of Sun engineers, and other Sun engineers sometimes lurk around).

This engineer pointed out that if Eden was full, and an object was about to be created, then if sufficient space could be freed in Eden, the object could be created there with no more work. But if sufficient space could NOT be freed, then existing objects in Eden had to be promoted to old space before the new object could be created. It could be that the application was finished with an object, but it had not yet gone out of scope, so could not be immediately garbage collected. Explicitly nulling the variable referencing that object would make a difference.

For those of you not up to spec on HotSpot GC, the heap is divided into several spaces: Eden and two survivor spaces (the three spaces collectively make up the young generation space) and an old generation space. Objects are created in Eden, and most objects die there and are reclaimed quickly. The two survivor spaces are for copying live objects so that young objects can remain in the young generation space for a time. If objects get too old, or young generation space gets full up, objects get promoted to the old generation space. If you need more detail, try this article Tuning Garbage Collection with the 1.3.1 Java Virtual Machine.

This being a gaming discussion board, the code example the engineer gave was relevant to animation, and a variation of his example follows here.

import java.awt.Image;
import java.awt.image.BufferedImage;

public class ImageGarbage1 {
  private static Image img;    //IMPORTANT 1
  public static void main(String args[]) {
    // Get one numerical argument which specifies size of image
    int imageSize = Integer.parseInt(args[0]);
    long startTime = System.currentTimeMillis();
    int imgIndex = 0;
    long loopIndex = 0;
    while (true) {
      //img = null;   //IMPORTANT 2
      // Create an image object
      img = new BufferedImage(imageSize, imageSize, 
        BufferedImage.TYPE_INT_RGB);
      long endTime = System.currentTimeMillis();
      ++loopIndex;
      // We print stats for every two seconds
      if (endTime - startTime >= 2000) {
        // Images created and disposed if per second
        long ips = (loopIndex / ((endTime - startTime) / 1000));
        System.out.println("IPS = " + ips);
        startTime = endTime;
        loopIndex = 0;
      }
    }
  }
}

Basically, this class repeatedly creates and discards images, measuring the rate of object creation, and printing that rate every couple of seconds. A single command line argument allows the size of the object to be specified.

On my desktop, I get the following results on running this:

COMMAND: java -version
java version "1.4.1_01"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1_01-b01)
Java HotSpot(TM) Client VM (build 1.4.1_01-b01, mixed mode)

COMMAND: java ImageGarbage1 361
IPS = 14
IPS = 18
IPS = 19
IPS = 19

Your machines are probably a darn sight more powerful than my old desktop [hk: goodness me, even my 2 year old notebook is faster ;-], so I'm sure you'll get larger numbers. You need to control-C the process to stop it, otherwise it runs forever. Now let's look at what happens if I uncomment the line labelled "IMPORTANT 2", which simply adds a null assignment to the static variable before creating the image object:

COMMAND: java ImageGarbage2 361
IPS = 116
IPS = 160
IPS = 164
IPS = 165
IPS = 151

Yes, that's right, the null assignment made the test run an order of magnitude faster! Well I guess that's a pretty definitive answer to the question of whether nulling variables makes a difference. What is happening in the first test (ImageGarbage1) is that the image is created in Eden, and when the next image is created, the first image is still hard referenced by the application, so the GC has to promote the object to the old generation to make space for the new object. In the second test (ImageGarbage2), the inserted null reference means that the existing image in Eden is not referenced by the application, and can be discarded.

However, before you go off changing your coding style, I should point out that this is a specially constructed case. The image size was carefully chosen to fill Eden. Look what happens when we increase the image size slightly, even with the null assignment:

 
COMMAND: java ImageGarbage2 362
IPS = 13
IPS = 18
IPS = 18
IPS = 19

In this last test, the image is too big to fit into the young generation, and gets created directly in the old generation each time. Which means that a full mark-sweep GC of the old generation is needed to reclaim the space, rather than the much faster copying GC of the young generation. And if we choose a much smaller size, so that several images fit into Eden, then each subsequent image assignment releases the reference to the previous image, so allowing them all to be collected in Eden:

 
COMMAND: java ImageGarbage1 100
IPS = 759
IPS = 1487
IPS = 1490
IPS = 1490

COMMAND: java ImageGarbage2 100
IPS = 810
IPS = 1611
IPS = 1621
IPS = 1613

Let's make one more change. I'll go back to the original version of the test, with the null assignment commented out. But this time I'll change the static variable definition (the line labelled "IMPORTANT 1") into a local variable in the main() method. Now look what happens when I run the test with the image just fitting into Eden:

 
COMMAND: java ImageGarbage3 361
IPS = 113
IPS = 157
IPS = 165
IPS = 166
IPS = 156

We get back to the same performance as the test with the null assignment, even though we are NOT making that null assignment this time. In this case, the compiler is intelligent enough to work out the scope of the image object, and has dereferenced it before the next assignment, so allowing it to be reclaimed before the next image is created.

Finally, putting together what we've seen, it's easy to work out that Eden's size was the real problem with the original test. So let's get back to that original case, and simply alter the size. Here I simply set the initial heap size larger than the default, which makes Eden proportionately larger:

 
COMMAND: java -Xms16M ImageGarbage1 361
IPS = 78
IPS = 129
IPS = 120
IPS = 131

And the same test with the slightly larger image, that previously had to be created in old generation space:

 
COMMAND: java -Xms16M ImageGarbage1 362
IPS = 73
IPS = 120
IPS = 121
IPS = 121

So there is no real need to change your coding style. Tuning the garbage collection is probably a more sensible solution. Does nulling variables improve garbage collection? Maybe, sometimes.

Jack Shirazi is the author of "Java Performance Tuning" (O'Reilly), and director of JavaPerformanceTuning.com. JavaPerformanceTuning.com lists three thousand performance tuning tips and publishes a monthly newsletter with all the latest Java performance news, tips, discussions, and more. See https://www.javaperformancetuning.com/

--Jack Shirazi
jack@JavaPerformanceTuning.com
https://www.javaperformancetuning.com

 

Comments

We are always happy to receive comments from our readers. Feel free to send me a comment via email or discuss the newsletter in our JavaSpecialists Slack Channel (Get an invite here)

When you load these comments, you'll be connected to Disqus. Privacy Statement.

Related Articles

Browse the Newsletter Archive

About the Author

Heinz Kabutz Java Conference Speaker

Java Champion, author of the Javaspecialists Newsletter, conference speaking regular... About Heinz

Superpack '23

Superpack '24 Our entire Java Specialists Training in one huge bundle more...

Free Java Book

Dynamic Proxies in Java Book
Java Training

We deliver relevant courses, by top Java developers to produce more resourceful and efficient programmers within their organisations.

Java Consulting

We can help make your Java application run faster and trouble-shoot concurrency and performance bugs...