Re: Do any Java compilers or JVMs optimize getter method calls?
On Sep 3, 3:56 pm, Lew <no...@lewscanon.com> wrote:
david.karr wrote:
I prefer to reference instance variables through getters, as opposed
to direct access to them. However, there's "obviously" going to be a
small time penalty for that. I did some timings in Eclipse, and I
found direct reads were a tiny fraction faster than through the getter
call (no surprise), and the difference between the setter and a direct
write was even smaller (I tested 100000000 iterations, adding up the
nanosecond intervals of each type of access).
I'm wondering whether there are any compiler/JVM combinations that
optimize getter calls to be the same as a direct access? I can see
from the bytecode in Eclipse that there is no optimization at that
level, but I don't know if the JVM will do any optimization in some
cases. It didn't appear to do it in Eclipse, but I don't know if other
JVMs would act differently.
You cannot tell optimization from the bytecode, because optimization happ=
ens
in the JVM.
Yes, I know, I was just pointing out the bytecode wasn't already pre-
optimized.
Doesn't Eclipse use the JVM installed on your system? What JVM is inst=
alled
on your system?
Yes. I've tested with Sun's 1.5.0_19, 1.6.0_14, and 1.6.0_16.
What options are you passing to the JVM now?
The most significant optimizations occur with the "-server" option to the
"java" command (or equivalent). Others are possible. They are docum=
ented on
java.sun.com and elsewhere.
I wasn't using "-server" before, but I am now. That's a useful
change.
Methods declared as 'final' tend to be inlined and run faster than method=
s not
so qualified.
When running your benchmarks, let the loop run a bunch of times before yo=
u
start timing. That lets the Hotspot compiler analyze the run and figur=
e out
what to optimize.
I'm also using both of these strategies. I'm running 100000000 timed
iterations, so I doubt the warm-up loop is necessary, but I'm doing
that anyway.
My measurements show very tiny differences (perhaps .02% total
difference over all 100000000 iterations). In fact, emphasizing the
fact that this isn't statistically significant, I saw several runs
where the "direct" test was slightly slower than the "getter" test.
If it matters, following this is my test class.
------Timings.java----------
package timings;
public class Timings {
private String foo;
final public String getFoo() {return foo;}
final public void setFoo(String foo) {this.foo = foo;}
public static void main(String[] args) {
Timings timings = new Timings(args);
timings.go();
}
public Timings(String[] args) {}
private void go() {
// warmup loop.
for (int ctr = 0; ctr < 1000; ++ ctr) {
setFoo(ctr + "");
getFoo();
this.foo = this.foo + "";
}
int iters = 10000000;
long totalns;
totalns = 0;
for (int ctr = 0; ctr < iters; ++ ctr) {
setFoo(ctr + "");
long startTime = System.nanoTime();
String val = getFoo();
totalns += (System.nanoTime() - startTime);
}
System.out.println("getter[" + totalns + "]");
totalns = 0;
for (int ctr = 0; ctr < iters; ++ ctr) {
setFoo(ctr + "");
long startTime = System.nanoTime();
String val = this.foo;
totalns += (System.nanoTime() - startTime);
}
System.out.println("direct[" + totalns + "]");
totalns = 0;
for (int ctr = 0; ctr < iters; ++ ctr) {
long startTime = System.nanoTime();
setFoo(ctr + "");
totalns += (System.nanoTime() - startTime);
}
System.out.println("setter[" + totalns + "]");
totalns = 0;
for (int ctr = 0; ctr < iters; ++ ctr) {
long startTime = System.nanoTime();
this.foo = ctr + "";
totalns += (System.nanoTime() - startTime);
}
System.out.println("direct[" + totalns + "]");
}
}
--------------------