为什么static/member变量比局部变量慢?

gam*_* on 3 java performance bytecode

我见过这个帖子:如果与条件相比的速度

我自己上课检查速度

public class Question {
static long startTime;
static long elapsedTime;

static String mStatic;
private String mPublic;

public static void main(String[] args) {
    Question q = new Question();
    q.executeGlobal();
    q.executeStatic();
    q.executeLocal();
}

public void executeLocal() {
    String mLocal;
    startTime = System.nanoTime();
    for (int i = 0; i < 1000000000; i++) {
        mLocal = "";
    }
    elapsedTime = System.nanoTime() - startTime;
    System.out.println("Type Local: " + elapsedTime + " ns");

}

public void executeGlobal() {
    startTime = System.nanoTime();
    for (int i = 0; i < 1000000000; i++) {
        mPublic = "";
    }
    elapsedTime = System.nanoTime() - startTime;
    System.out.println("Type Global: " + elapsedTime + " ns");

}

public void executeStatic() {
    startTime = System.nanoTime();
    for (int i = 0; i < 1000000000; i++) {
        mStatic = "";
    }
    elapsedTime = System.nanoTime() - startTime;
    System.out.println("Type Static: " + elapsedTime + " ns");
}

}
Run Code Online (Sandbox Code Playgroud)

结果:

Type Global: 45693028 ns
Type Static: 43853723 ns
Type Local: 2057505 ns
Run Code Online (Sandbox Code Playgroud)

在答案中@Rod_algonquin回答说,这是因为静态变量的getstatic/putstatic字节码和成员变量的getfield/putfield字节码,它是通过位移和一些加法来计算的.

起初我以为只有对象会导致这种情况,但在尝试引用原语时,结果相同local variable仍然更快.

为什么局部变量更快?字节码解释除外.

dgm*_*dgm 9

通常,jvm使用三个不同的内存段

  1. 堆 - 包含运行时中的所有已创建对象,仅包含对象及其对象属性(实例变量)
  2. 堆栈 - 包含局部变量和引用变量(保存堆中对象地址的变量)
  3. 代码段 - 加载时实际编译的Java字节码所在的段

堆栈值仅存在于它们创建的函数范围内.一旦返回,它们将被丢弃.

然而,堆值存在于堆上.它们是在某个时间点创建的,并在另一个时间点被破坏(通过GC或手动).Java仅在堆栈上存储基元.这使堆栈保持较小并有助于保持单个堆栈帧较小,从而允许更多嵌套调用.在堆上创建对象,并且只在堆栈上传递引用(而这些引用又是基元).

Java使用三种不同的变量

  • 静态变量: - 类变量称为静态变量.每个类加载器每个JVM只出现一次类变量.加载类时,初始化类变量(也称为静态变量).它们位于类(字节码)所在的位置,位于代码段中
  • 实例变量: - 实例变量是非静态的,每个类实例(即每个对象)中都会出现一个实例变量.也称为成员变量或字段.
  • 局部变量:局部变量的范围比实例变量的范围窄.局部变量的生命周期由执行路径决定

访问堆栈的速度相对较快(但它纯粹是JVM实现特定的),而不是代码段,因此访问本地变量比全局更快.

有关详细信息,您可以查看http://blog.jamesdbloom.com/JVMInternals.htmlit-haggar_bytecode

还有另一篇文章分析静态与局部变量的性能


rad*_*dai 5

你是运行时优化的牺牲品:-)

如果你稍微改变你的代码:

Question q = new Question();
for (int i=0; i<2; i++) {
    q.executeGlobal();
    q.executeStatic();
    q.executeLocal();
}
Run Code Online (Sandbox Code Playgroud)

你得到这个:

Type Global: 38331943 ns
Type Static: 57761889 ns
Type Local: 3010189 ns
Type Global: 46249688 ns
Type Static: 52745009 ns
Type Local: 0 ns
Run Code Online (Sandbox Code Playgroud)

发生的事情很快就是运行时很快意识到你的局部变量不断被分配,但永远不会被读取(或使用),并优化整个循环.

至于类实例字段和静态字段之间的区别,它们都在堆上,但静态字段在所有对象实例之间共享,因此有一个额外的间接级别