Why does Method access seem faster than Field acce

2019-04-27 05:51发布

问题:

I was doing some tests to find out what the speed differences are between using getters/setters and direct field access. I wrote a simple benchmark application like this:

public class FieldTest {

    private int value = 0;

    public void setValue(int value) {
        this.value = value;
    }

    public int getValue() {
        return this.value;
    }

    public static void doTest(int num) {
        FieldTest f = new FieldTest();

        // test direct field access
        long start1 = System.nanoTime();

        for (int i = 0; i < num; i++) {
            f.value = f.value + 1;
        }
        f.value = 0;

        long diff1 = System.nanoTime() - start1;

        // test method field access
        long start2 = System.nanoTime();

        for (int i = 0; i < num; i++) {
            f.setValue(f.getValue() + 1);
        }
        f.setValue(0);

        long diff2 = System.nanoTime() - start2;

        // print results
        System.out.printf("Field Access:  %d ns\n", diff1);
        System.out.printf("Method Access: %d ns\n", diff2);
        System.out.println();
    }

    public static void main(String[] args) throws InterruptedException {
        int num = 2147483647;

        // wait for the VM to warm up
        Thread.sleep(1000);

        for (int i = 0; i < 10; i++) {
            doTest(num);
        }
    }

}

Whenever I run it, I get consistent results such as these: http://pastebin.com/hcAtjVCL

I was wondering if someone could explain to me why field access seems to be slower than getter/setter method access, and also why the last 8 iterations execute incredibly fast.


Edit: Having taken into account assylias and Stephen C comments, I have changed the code to http://pastebin.com/Vzb8hGdc where I got slightly different results: http://pastebin.com/wxiDdRix .

回答1:

The explanation is that your benchmark is broken.

The first iteration is done using the interpreter.

Field Access:  1528500478 ns
Method Access: 1521365905 ns

The second iteration is done by the interpreter to start with and then we flip to running JIT compiled code.

Field Access:  1550385619 ns
Method Access: 47761359 ns

The remaining iterations are all done using JIT compiled code.

Field Access:  68 ns
Method Access: 33 ns

etcetera

The reason they are unbelievably fast is that the JIT compiler has optimized the loops away. It has detected that they were not contributing anything useful to the computation. (It is not clear why the first number seems consistently faster than the second, but I doubt that the optimized code is measuring field versus method access in any meaningful way.)


Re the UPDATED code / results: it is obvious that the JIT compiler is still optimizing the loops away.