避免 getfield 操作码

Posted

技术标签:

【中文标题】避免 getfield 操作码【英文标题】:Avoiding getfield opcode 【发布时间】:2011-06-13 07:09:41 【问题描述】:

在 Java 的 String 类中,trim 方法包含以下内容:

int off = offset;      /* avoid getfield opcode */
char[] val = value;    /* avoid getfield opcode */

我对 "avoid getfield opcode" 的评论有点困惑...

这是什么意思? (我认为这避免了在字节码中使用 getfield,但为什么这是一件好事 [TM]?)

如果 trim 不执行任何操作(因此返回 this),是否阻止创建对象?

【问题讨论】:

【参考方案1】:

getfield用于获取类的成员变量。

从剩下的代码可以看出:

while ((st < len) && (val[off + st] <= ' ')) 
    st++;

while ((st < len) && (val[off + len - 1] <= ' ')) 
    len--;

因此,当您处于循环中时,每次引用 valueoffset 时,它都必须执行 getfield。如果循环运行很长时间(因为每次测试循环条件时,offsetvalue 都会执行getfield),您可能会招致很大的性能损失。因此,通过使用局部变量 offval,可以降低性能损失。

【讨论】:

同意,除了这仅对非优化代码有效。当 JIT 参与进来时,它就不再重要了。 JIT 可能通过将值放入寄存器来进行优化;它是微不足道的,因为它是完全等价的。价值是最终的,这是显而易见的。但即使没有它也有可能。 JIT 可以对此进行优化。例如,不要指望在 Dalvik 上进行这种优化。出于其他原因,将字段拉入本地可能很有用,例如对可以同时访问的字段进行空检查。【参考方案2】:

我的猜测是关键是将值复制到局部变量中一次,以避免在接下来的几行中每次循环迭代都必须从堆中重复获取字段值。

当然,这引出了一个问题,即为什么没有对“len”局部变量应用相同的注释。 (我还希望 JIT 无论如何都避免重新获取,尤其是在变量是最终变量的情况下。)

【讨论】:

注释不适用于 'len' 因为 len 在方法中被主动修改,所以无论如何它必须是一个局部变量。另一方面,'off' 和 'val' 没有被修改,只是为了优化而存在。 @Lars:很好看;我没有看到 len 的变化。 @JonSkeet 如果您亲自编写这个库,您是否认为自己会这样做?还是仅仅依靠 JIT 进行微优化? @corsiKa:我会先编写最简单的代码,然后对其进行分析。如果这暗示了微优化,我可能会应用它。

以上是关于避免 getfield 操作码的主要内容,如果未能解决你的问题,请参考以下文章

Class.getFields() 返回的字段顺序

反射之getField()与getDeclaredField()的区别

Java反射中getFields和getDeclaredFields有啥区别

getField()与getDeclaredField()的区别

为啥 Type.GetFields() 不返回基类中的支持字段?

class.getFields和class.getDeclareFields的区别