Feb 08 2006

Object Burn is Your Friend

Published by Robert Fischer at 2:49 pm under To Be Categorized

Okay, there’s one, huge, bug-spawning pet peeve of mine in coding Java: premature declaration.

If you have a value that is being used often, and you want to cache it, feel free to make it a private final variable, preferably a private static final variable. Be my guest.

However, as a general rule, you should allocate something when you need it, and let it fall out of scope almost immediately after you’re done using it. If you “accidentally” use it at an inappropriate spot, the compiler will catch that. Garbage collection will thank you.

The most common cause for bugs (and biggest waste of memory) is the one-off instance member variable. Because declaring objects is “expensive” in Java you find all kinds of weird hacks of moving variables that are only used in one method out into the actual body of the object. All of the problems that people hate about global variables then starts to be subject in that class for that variable. On top of it, you’ve then just made the class thread-unsafe unless you do some dangerous synchronization backflips to try to secure it.

Similarly, if you’re using a loop variable, declare it within the loop, not outside. Yes, you’ll produce lots of garbage. That’s fine — that’s why you have a garbage collector. On the other hand, you then don’t have to worry about as many naming issues, and your object vanishes much sooner. On top of it, this kind of coding style allows you to use the “final” modifier with great abundance, which makes your code much easier to read and maintain.

If you need to speed up your code, and you can prove that the bottleneck is in object creation at this area of code, and you are certain that there’s no better algorithm to be using, then and only then can you start to consider premature declaration. I would instead suggest creating a Factory class (probably utilizing Commons-Pool), though. You’re almost always gonig to be better-served at that point, because you are going to be solving the underlying problem (instantiating the Foo class is expensive) instead of the surface problem (this code instantiates a lot of Foo objects).

Popularity: 6% [?]

7 Responses to “Object Burn is Your Friend”

  1. bhurt-awon 08 Feb 2006 at 7:24 pm

    There are several problems here. The first, and most obvious, is programmers prematurely optimizing again. I know programmers who worry immensely about object creation speed, but don’t think (and occassionally don’t even know about) the big-O costs of their algorithms. They usually, sooner or later, end up writting highly but badly tuned bubble sorts.

    The second problem is Java reinventing the wheel- only this time they’re making it octogonal, which works oh so much better than the old square wheels. When right over there people are making round wheels, which while more complicated than square or triangular wheels, are simpler than and work better than, even octogonal wheels. Java object allocation should never have been slow, it should have been fast on day one. They should have talked to the functional programming people, who knew about GC and how to make it fast, and gotten them to help. They still haven’t, so they’re laborously reinventing what the functional people knew decades ago.

    Take tuning GC, for example. The new GC in Java 1.5 has lots of parameters to tune, which is a classic warning sign that you’re not tuning the right thing. In any Java developers read this, here’s a free hint: the one parameter you need to look at to tune GC is what percentage of objects scanned are garbage, and you want that percentage to be 50%. If 50% of the objects scanned are garbage, this means on average each object is only scanned twice before it becomes garbage, thus limiting the computational cost of GC. Also, it means that you’re only using about 2x as much memory as you absolutely need to (which is also the best gaurentee that malloc/free can give you, due to fragmentation problems), so you also limit the amount of wasted memory.

    Note that there is a broad valley floor around the 50% mark- wide variations in percentages are acceptable. If only 25% of the objects being scanned are garbage, that means each object is scanned on average four times before it becomes garbage- you’re doing more work than you really want to, but not much, and you have much less wasted memory. While if 75% of the objects being scanned are garbage, you’re using four times as much memory as you need to, but on average you’re only scanning each object a little more than once on average before it becomes garbage. So if you’re anywhere in the 25-75% range, you’re probably good enough for most programs. It’s perfectly reasonable to hardcode the collector to aim for 50%, and have no tunable parameters at all. The fact that the Java developers gave multiple tuning parameters, but not this one, proves they still don’t understand GC.

    The third problem is that Java doesn’t provide enough ways to limit the life expectancy of a variable, especially when dealing with overlapping variable lifetimes. For example, I will oftentimes have code like:

    Object a = some complicated expression;
    Object b = some complicated expression using a;
    Object c = some complicated expression using b but not a;

    The lifetimes of objects a and c do not overlap, but both overlap the lifetime of object b. In Ocaml, I could write:

    let c =
    let b =
    let a = some complicated expression in
    some complicated expression using a
    in
    some complicated expression using b but not a

    I’m not sure how I can limit the lifetime of a such that once b’s value is calculated, a is garbage, but not b. I suppose I could do:

    Object a = …;
    Object b = …;
    a = null; /* Allow a to be collected */
    Object c = …;
    b = null; /* Allow b to be collected */

    But there is no way to tell Java that we’re done with a.

  2. Candideon 08 Feb 2006 at 8:59 pm

    I’ve taken to actually doing something this:

    final Object c;
    do {
         final Object b;
         do {
              final Object a = ...;
              b = ...;
         };
         c = ...;
    };
    somethingInterestingWithC(c);
    

    Or something. That may not compile — Java may require the while(false) part at the end.

  3. TheHawkon 09 Feb 2006 at 10:06 am

    Why not just ditch the do? You don’t mean it and don’t need it.

  4. Candideon 09 Feb 2006 at 10:48 am

    I do mean it: I want to do what’s in the brackets.

    If I had a choice between do {} while(false) and {}, I’d take the latter. On the other hand, if I can say do {}, I’ll do that over either option, because I’ve got a nasty tendency of not seeing lone brackets. So I think do {} is clearer and more maintainable than just brackets floating around.

    Originally, I just used brackets, but I found myself writing code like this:

    { // Scoping brace

    } // End scoping brace

    After doing that a couple of times, I decided it was easier on my fingers, eyes, and code to write that as do {}.

  5. TheHawkon 09 Feb 2006 at 2:36 pm

    You don’t want to do whats in the brackets anymore then whats outside the brackets. By that logic, you might as well enclose the whole method in a do {}. Also, just use the standard indentation to denote code within the braces. That visual break is about the same as you get with the do block and should be sufficient to catch your eye.

  6. Candideon 09 Feb 2006 at 2:48 pm

    Sure, you can enclose anything you want in a do{} block. That’s the fun of them.

    I take it back, BTW. Recent experimentation illustrates that Java doesn’t like do{} — that’s a Perlism in my code, apparently. So, with Java, I do use the unadorned bracket syntax like you’ve been suggesting.

  7. [...] you’ve been declaring variables at the point of assignment, as I’ve been advocating ([1], [2], [3]), then you already know that you can usually get rid of null without missing it [...]

Trackback URI | Comments RSS

Leave a Reply

Green Web Hosting! This site hosted by DreamHost.