So my question is about variable accessing speed in Java. Today in my "CS" (if you can call it that) the teacher presented a similar example to the following of a List:
public class ListExample<T> {
private Node<T> head;
private Node<T> tail;
private class Node<T> { /* ... */ }
public void append(T content) {
if (!isEmpty()) {
Node<T> dummy = new Node<T>(content);
head = dummy;
tail = dummy;
head.setNext(head);
// or this
dummy.setNext(dummy);
} else { /* ... */ }
}
// more methods
// ...
}
My question is: Would the call to head.setNext(head)
be slower than dummy.setNext(dummy)
? Even if it's not noticeable.
I was wondering this since head
is obviously and instance var of the class and dummy is local, so would the local access be faster?
Local (temporary) variables and method-argument variables are the fastest variables to access and update.
Instance variables are declared in a class, but outside a method, constructor or any block. Class variables also known as static variables are declared with the static keyword in a class, but outside a method, constructor or a block.
Ok, I've written a micro-benchmark (as suggested by @Joni & @MattBall) and here are the results for 1 x 1000000000 accesses for each a local and an instance variable:
Average time for instance variable access: 5.08E-4
Average time for local variable access: 4.96E-4
For 10 x 1000000000 accesses each:
Average time for instance variable access:4.723E-4
Average time for local variable access:4.631E-4
For 100 x 1000000000 accesses each:
Average time for instance variable access: 5.050300000000002E-4
Average time for local variable access: 5.002400000000001E-4
So it seems that local variable accesses are indeed faster that instance var accesses (even if both point to the same object).
Note: I didn't want to find this out, because of something I wanted to optimize, it was just pure interest.
P.S. Here is the code for the micro-benchmark:
public class AccessBenchmark {
private final long N = 1000000000;
private static final int M = 1;
private LocalClass instanceVar;
private class LocalClass {
public void someFunc() {}
}
public double testInstanceVar() {
// System.out.println("Running instance variable benchmark:");
instanceVar = new LocalClass();
long start = System.currentTimeMillis();
for (int i = 0; i < N; i++) {
instanceVar.someFunc();
}
long elapsed = System.currentTimeMillis() - start;
double avg = (elapsed * 1000.0) / N;
// System.out.println("elapsed time = " + elapsed + "ms");
// System.out.println(avg + " microseconds per execution");
return avg;
}
public double testLocalVar() {
// System.out.println("Running local variable benchmark:");
instanceVar = new LocalClass();
LocalClass localVar = instanceVar;
long start = System.currentTimeMillis();
for (int i = 0 ; i < N; i++) {
localVar.someFunc();
}
long elapsed = System.currentTimeMillis() - start;
double avg = (elapsed * 1000.0) / N;
// System.out.println("elapsed time = " + elapsed + "ms");
// System.out.println(avg + " microseconds per execution");
return avg;
}
public static void main(String[] args) {
AccessBenchmark bench;
double[] avgInstance = new double[M];
double[] avgLocal = new double[M];
for (int i = 0; i < M; i++) {
bench = new AccessBenchmark();
avgInstance[i] = bench.testInstanceVar();
avgLocal[i] = bench.testLocalVar();
System.gc();
}
double sumInstance = 0.0;
for (double d : avgInstance) sumInstance += d;
System.out.println("Average time for instance variable access: " + sumInstance / M);
double sumLocal = 0.0;
for (double d : avgLocal) sumLocal += d;
System.out.println("Average time for local variable access: " + sumLocal / M);
}
}
In general, an access to an instance variable (of the this
object) requires an aload_0
(to load this
to the top of the stack) followed by getfield
. Referencing a local variable requires only the aload_n
to pull the value out of its assigned location in the stack.
Further, getfield
must reference the class definition to determine where in the class (what offset) the value is stored. This could be several additional hardware instructions.
Even with a JITC it's unlikely that the local reference (which would normally be zero/one hardware operation) would ever be slower than the instance field reference (which would have to be at least one operation, maybe 2-3).
(Not that this matters all that much -- the speed of both is quite good, and the difference could only become significant in very bizarre circumstances.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With