繁体   English   中英

Java中的本地参考优化

[英]local reference optimization in Java

void myMethod(Object arg)
{
    arg.getThing().method1();
    arg.getThing().method2();
}

基本的Java 6安装是否会将其优化为对访问器的单个调用(可能通过将引用存储在本地)。 我意识到如果有多个线程,优化器可能不得不这样做。 几乎所有Java 6 JVM都有我可以期待的常见优化列表吗?

例:

    {
       Object local = arg.getThing();
       local.method1();
       local.method2();
    }

我不希望javac编译器在这里进行任何优化,因为getThing()的值可以随时间和调用之间的变化(例如,堆栈上的随机值或pop()操作或当前时间。你明白了。

也许JIT编译器可以优化它,如果它看到getThing()方法总是返回相同的东西,但我不会指望它。 即便是最简单的return thing; 如果thing的值被另一个线程更改,则statement可以返回不同的值。

这不会被javac优化,也不会像JVM建议的那样进行优化。 可能发生的是内联然后优化。

例如

arg.getThing().method1();
arg.getThing().method2();

变成

Thing a = arg.thing;
a.method1();
Thing b = arg.thing;
a.method2();

变成

Thing a = arg.thing;
// expands a.method1(); doesn't update arg.thing.
Thing b = arg.thing;
// expands b.method2();

变成

Thing a = arg.thing;
// expands a.method1(); doesn't update arg.thing.
// expands a.method2();

当内联足够的代码以确定安全时,可以消除对thing的重复查找。 除非所有方法都是微不足道的,否则这通常不会发生(或产生很大的不同)。

如果getThing是一项昂贵或复杂的操作,则极不可能进行优化,您最好自己缓存结果。 (因为JIT不太可能确定其缓存值的安全性)

如果任何具有不具有副作用的函数的语言能够将函数的多个调用优化为一个,我会发现它非常令人惊讶。 如果getThing()存储了某些内容(例如,访问了多少次),该怎么办? 编译器甚至可以说出来吗?

如果method1修改了thing引用或者第二次调用的某种更改,该怎么办?

虽然这种优化基本上没有任何改变,但为了确保编译器能够安全地优化,你应该写:

void myMethod(Object arg) {
    final Thing thing = arg.getThing();
    thing.method1();
    thing.method2();
}

没有优化会使您免于NullPointerException ,您的代码将更加健壮,因为:

Object local = arg.getThing();
if (null != local) {
   local.method1();
   local.method2();
}

完全有可能jit编译器内联对getThing调用,然后通过commons子表达式消除来优化它。 我不会依赖于这种行为,因为内联取决于getThing方法的大小。 也许你的方法现在是一个简单的getter,但是由于一些重构,这可能会改变。

我过去的一个例子是getter返回一个Object[] ,它是通过在Collection上调用toArray实现的。 吸气剂在循环中被调用,突然变为线性变为二次运行时。

比编译器是否优化这一点更重要的是将您的意图传达给您的同事和您未来的自我。 如果你的代码确实希望两次运行相同的Thing ,那么你应该将它存储在局部变量中,允许你自由地重构getter方法。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM