Variable scope efficiency
I realize similiar questions have been asked elsewhere in the forums, but all the answers I'm seeing are "I think..." and "I would assume..." and things of this nature. I'm looking for a concrete answer from someone with a solid understanding of how the JVM works.
The question is this: If an instance variable will be accessed many times during a particular routine (like in a method), is it more efficient to copy the value into a local variable?
The motivation for the question is based on my mediocre understanding of compilers. As I understand it (for traditional machine language compilers, not for the JVM), the value of an instance member is stored at some location in memory which needs to be calculated based on the address of the owning object, and a particular offset for that field, where as local variables are on either the stack or the frame, the base pointers for which are more or less consistent throughout a method/function. So it seems to me that figuring out where the value for an instance variable is being stored would take more effort than pulling it off the stack or out of the frame. I don't know if this is actually the case though, and I definitely don't know if the Java architecture works this way.
So any insight would be appreciated.
Thanks.
-Brian
# 1
There is one very big difference - if you copy the variable, you know it won't be modified without your knowledge. This means it can be cached in register. On the other hand, if you access field from the object, every read will impose memory access.
Badly implemented jit compiler could have same cost for both cases, but hotspot is smart enough to put frequently used local variables into registers.
Just in case somebody thinks that compiler can cache even object field access in case of no synchronization, consider following code
void method(MyObject a, MyObject b) {
System.out.println(a.value);
b.value = 5;
System.out.println(a.value);
}
Can a.value be cached in register, even if we ignore other threads? Only if you can prove that b != a - but with more complicated examples jit would have to spend too much effort to save one memory access.
So to answer you question, local variables are faster for _mutable_ values, because compiler is allowed to cache them in registers.
For the final variables (especially array.length) there is nothing which would stop Hotspot from caching them - but I cannot say if it does that.
# 2
Generally the compiler is able to avoid reloads of a value when the previous load could be reused but the ability to do so varies greatly between compilers and source code. As the code gets larger and more complex it becomes harder. It also becomes less helpful as the code gets larger so simple version often get pretty good results. On the other hard avoiding the reload can sometimes allow you to eliminate large expressions that were previously computed and can eliminate a fair amount of work. The client compiler does an ok job with this but doesn't attempt to do the best possible job. The server compiler does very well but without interprocedural analysis it's very hard to do this in all cases.
As the previous poster points out, if your code caches a copy itself you guarantee that we don't have to reload so you're not relying on the compiler to do it for you. Sometimes this can help code which is very tight and for whatever reason the compiler is unable to prove that the old value is still safe to use. A lot of this depends on alias analysis where the compiler has to figure if two objects could be the same or not. The method example above illustrates a case where it's extremely hard to a compiler to prove these things are different. if you are operating on multiple variables of the same type it's very hard for the compiler to prove that they are different so sometimes you can help out but caching them yourself.
Generally though it's not a good idea to cache loads in everything you write since it can introduce bugs and it makes the code more verbose and harder to maintain. This is something you might do to make a fast piece of code faster, like some computation kernel.
Even C compilers can have trouble with this. In fact Java has it a little easier because the type system doesn't allow arbitrary casts. So the JIT compiler knows that two unrelated types can't alias each other but in C they could.
tom
# 3
> I realize similiar questions have been asked
> elsewhere in the forums, but all the answers I'm
> seeing are "I think..." and "I would assume..." and
> things of this nature. I'm looking for a concrete
> answer from someone with a solid understanding of how
> the JVM works.
>
> The question is this: If an instance variable will be
> accessed many times during a particular routine (like
> in a method), is it more efficient to copy the value
> into a local variable?
>
> The motivation for the question is based on my
> mediocre understanding of compilers. As I understand
> it (for traditional machine language compilers, not
> for the JVM), the value of an instance member is
> stored at some location in memory which needs to be
> calculated based on the address of the owning object,
> and a particular offset for that field, where as
> local variables are on either the stack or the frame,
> the base pointers for which are more or less
> consistent throughout a method/function. So it seems
> to me that figuring out where the value for an
> instance variable is being stored would take more
> effort than pulling it off the stack or out of the
> frame. I don't know if this is actually the case
> though, and I definitely don't know if the Java
> architecture works this way.
>
Huh?
I you have the following operations.....
1. X.doit()
2. Y.Op1().Op2().Op3().doit()
Then 1 will always be faster than 1.
And JIT is not going to optimize it except in some very unusual situations.
Local variables ARE on the stack. There is no other place for them to exist.
If you are accessing a member variable then it takes less instructions to access a local variable in comparison due to a dereference. The JIT might optimize this.
Note that none of this is relevant unless you have profiled your application and have actually determined where the bottlenecks are.
# 4
> I realize similiar questions have been asked
> elsewhere in the forums, but all the answers I'm
> seeing are "I think..." and "I would assume..." and
> things of this nature. I'm looking for a concrete
> answer from someone with a solid understanding of how
> the JVM works.
By the way that statement is impossible.
By definition a JVM instance is allowed to do anything any way it wants as long as it meets the specs. And the specs don't detail this.
And VM vary by version/build as well.
So without analyzing the source code for a specific build in detail no one can answer that question. Nor should anyone try in the vast majority of situations because basing decisions based on that would tie the application to that single build of the VM.
# 5
> There is one very big difference - if you copy the
> variable, you know it won't be modified without your
> knowledge. This means it can be cached in register.
> On the other hand, if you access field from the
> object, every read will impose memory access.
Which has nothing to do with speed of course.
>
> Badly implemented jit compiler could have same cost
> for both cases, but hotspot is smart enough to put
> frequently used local variables into registers.
>
I doubt that most routines would benefit from that in a measurable way. By the time a single routine because complex enough that it becomes a bottle neck, the savings by putting something in a register is below the noise level of the rest of the routine.
# 6
> > There is one very big difference - if you copy the
> > variable, you know it won't be modified without
> your
> > knowledge. This means it can be cached in
> register.
> > On the other hand, if you access field from the
> > object, every read will impose memory access.
>
> Which has nothing to do with speed of course.
I beg to differ. On main stream architectures, register operations will be not slower then memory ones, while you can always find a cases where memory ones will be a lot slower, depending on cache/ordering/etc.
> I doubt that most routines would benefit from that in
> a measurable way. By the time a single routine
> because complex enough that it becomes a bottle neck,
> the savings by putting something in a register is
> below the noise level of the rest of the routine.
Well, question was what is faster, not if it makes sense to optimize it. It is jvm forum, not best-practices forum.
Should I produce the microbenchmark to prove that memory operations are slower then register operations in measureable way?
# 7
> I'm looking for a concrete
> answer from someone with a solid understanding of how
> the JVM works.
>
> If an instance variable will be
> accessed many times during a particular routine (like
> in a method), is it more efficient to copy the value
> into a local variable?
You don't need someone with a solid understanding of how the JVM works to answer that.
Write up a small test and try it for yourself.
If you want to improve the quality of the metrics you get from this
make your test more elaborate and closer to your real-life code.
# 8
> > > There is one very big difference - if you copy the
> > > variable, you know it won't be modified without your
> > > knowledge. This means it can be cached in
> > register.
> > > On the other hand, if you access field from the
> > > object, every read will impose memory access.
> >
> > Which has nothing to do with speed of course.
>
> I beg to differ. On main stream architectures,
> register operations will be not slower then memory
> ones, while you can always find a cases where memory
> ones will be a lot slower, depending on
> cache/ordering/etc.
Yes and if one uses the assembler directive for doing a byte memory move in memory it will be faster than doing it with an assembly loop.
However I doubt that the vast majority of people who program in java will ever encounter a bottleneck situation where that sort of of time difference is measurable much less significant.
How much time am I going to save if the index variable of a for loop is in a register when the body of the for loop is doing a database transaction with 4 round trip updates and a query to the database?
>
> > I doubt that most routines would benefit from that in
> > a measurable way. By the time a single routine
> > because complex enough that it becomes a bottle neck,
> > the savings by putting something in a register is
> > below the noise level of the rest of the routine.
>
> Well, question was what is faster, not if it makes
> sense to optimize it. It is jvm forum, not
> best-practices forum.
>
> Should I produce the microbenchmark to prove that
> memory operations are slower then register operations
> in measureable way?
You should also write it in assembler to compare the time for that as well.If that sort of time is truely important then it will be relevant to see what sort of difference assembler makes versus java.
# 9
Well thanks everyone for the responses. So from the sounds of it, it is technically more efficient to reference a value locally than to dig up an instance variable. In the real world, it probably won't make any difference in the performance of my program, but that wasn't really the intent of the question so much as just a best practices understanding.
For those of you who suggest I time it; I've never done that in Java before, can you suggest how I would? I know I can get system time in millis, and do a big loop where the body accesses variables in the different ways, but won't it depend on the load on my machine?
-Brian
# 10
> ...but won't it depend on the load on my> machine?Yes.But regardless of what you do in code, the load on the machine will impact that. So that must be a consideration when designing the system (as opposed to implementing one routine.)