为什么有些Java 类方法中要cache类变量

比如以下一段java代码:

private void performTraversals() {
    // cache mView since it is used so much below...
    final View host = mView;

    ......
}

为什么要这么写呢?

下面用一段测试程序的bytecode来解释一下(以下bytecode是基于JVM的,不是基于art的):

public class TestLocal {
    private int i = 1;

    public void foo() {
        long before = System.currentTimeMillis();
        for (int j = 0; j < 10000; j++) {
            System.out.print(i);
        }

        System.out.println();
        System.out.println("TestLocal result: " + (System.currentTimeMillis() - before));
    }

    public static void main(String[] args) {
        new TestLocal().foo();
        new TestLocal2().foo();
    }
}


class TestLocal2 {
    private int i = 1;

    public void foo() {
        int k = i;
        long before = System.currentTimeMillis();
        for (int j = 0; j < 10000; j++) {
            System.out.print(k);
        }

        System.out.println();
        System.out.println("TestLocal2 result: " + (System.currentTimeMillis() - before));
    }
}

TestLocalfoo方法,直接读取类变量,对应的字节码是

        13: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
        16: aload_0
        17: getfield      #2                  // Field i:I
        20: invokevirtual #5                  // Method java/io/PrintStream.print:(I)V

每次都需要将this push到operand stack中,然后去堆里找对应的field。

TestLocal2foo方法,是将类变量的值存储在当前Frame的local variable中。然后每次调用只要从local variable中取用。

         0: aload_0
         1: getfield      #2                  // Field i:I
         4: istore_1
         .......
        20: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
        23: iload_1
        24: invokevirtual #5                  // Method java/io/PrintStream.print:(I)V

运行时间对比:

TestLocal result: 145 ms
TestLocal2 result: 128 ms

所以将类变量缓存到方法的local variable中还是能提升运行速度的,尤其是如果类变量会被经常访问。

推荐阅读更多精彩内容