2

I was reading Google's tips on Android optimisation, and one of the first points they bring up is that you should avoid using short-term variables because it means more garbage collection. So, is there a point where you'd be better off defining a variable and using that instead of calling a accessor every time you want to use the object? Say, this:

for(int i = 0; i < 1000; i++) {
    foo.getBar() // then do something with it
}

As opposed to this:

Bar bar = foo.getBar();
for(int i = 0; i < 1000; i++) {
    bar // then do something with it
}

What's the difference, performance-wise?

  • 2
    The point about garbage collection is relevant for class level variables. If you wanted to know whether its better to declare bar as a class level variable or a method local variable then it depends on how frequently you are going to access it and its life time. Within a method the second option is of course better. – appsroxcom Mar 25 '13 at 04:05

3 Answers3

3

From the link you provided: "you should avoid creating object instances you don't need to"

  1. object instances != short-term variables
  2. don't forget the second part of the sentence...

Local variables are usually allocated on the stack (where GC is irrelevant) while new object instances will be allocated on the heap - which is a totally different story. TMHO saying something like "don't do something if you don't really need to" has little value. Further, trying to avoid creating local variables when possible might have a really BAD effect on your code, read this

Community
  • 1
  • 1
Nir Alfasi
  • 53,191
  • 11
  • 86
  • 129
2

assuming no compiler optimizations

When you use

for(int i = 0; i < 1000; i++) {
    foo.getBar() // then do something with it
}

Your code will go to your instance referred by foo, execute its getBar() method, which will then return an instance/value of whatever it is supposed to return. This will be done for each and every one of your 1000 executions of that loop. After each execution is done, the value returned by getBar() will have to be garbage collected.

However, when you use:

Bar bar = foo.getBar();
for(int i = 0; i < 1000; i++) {
    bar // then do something with it
}

You get the value of foo.getBar() only once, outside your loop and store a copy of it locally. This local copy is then used in the loop 1000 times.

The second option is more efficient because your foo instance's getBar() method is called only once, instead of a thousand times. This means you don't execute the code in the getBar() method 1000 times, which is obviously worse than executing it once.

These are all really micro optimizations. Unless you are doing some real heavy lifting in getBar(), this won't have a noticeable effect. In a lot of cases, compiler optimizations will turn both of these into the exact same Bytecode, so you wouldn't worry about it anyways.

Raghav Sood
  • 81,899
  • 22
  • 187
  • 195
  • 1
    I don't think it make sense for the compiler to move the method invocation outside the loop for the sake of optimization. – Bhesh Gurung Mar 25 '13 at 04:17
  • @BheshGurung actually it does: whenever you call a method (assuming it returns the same result, for example, the value of a final variable or a reference to a static object) a new frame is created on the stack which has a "context switch" cost, and even if this cost is small, it's better to avoid it when possible. – Nir Alfasi Mar 25 '13 at 16:53
  • @alfasin: But how would the compiler know about that? AFAIK, the compiler doesn't care whether the value returned by a method is compile-time constant or not. I guess it would be possible if we could add the `final` keyword in front of the method return type :). – Bhesh Gurung Mar 25 '13 at 20:02
  • @BheshGurung Sounds to me like it should be rather easy to implement a compiler optimization for a method that returns a constant value (final/reference), but I might be wrong :) – Nir Alfasi Mar 25 '13 at 23:17
1

In this example, assuming bar is just an object returned by getBar and not created there is no difference as far as the GC is concerned.

However, method calls also have a small overhead and your second example will be more efficient.

However, if getBar creates a new object on each call, then 1000 new Bars will have created and then GCed in the second example whilst the first remains the same.

alex
  • 6,359
  • 1
  • 23
  • 21