【问题标题】:Is there a performance advantage to declaring a static value globally over a local variable in Java?在 Java 中全局声明静态值而不是局部变量是否有性能优势?
【发布时间】:2023-03-22 08:16:01
【问题描述】:

鉴于这些代码示例:

示例 1

public class SomeClass {
    private static final int onlyUsedByMethodFoo = 1;
    // many lines of code
    public static void foo() {
        final String value = items[onlyUsedByMethodFoo];
    }
}

示例 2

public class SomeClass {
    // many lines of code
    public static void foo() {
        final int onlyUsedByMethodFoo = 1;
        final String value = items[onlyUsedByMethodFoo];
    }
}

我更喜欢第二个代码示例,因为该值接近使用它的位置。无论如何,它仅由 Foo() 使用。即使经常调用 Foo() ,我也看不到将其声明为全局值的优势。我可以看到的全局静态值的唯一优势可能是性能,但目前还不清楚它会有多大的性能优势。也许 Java 意识到了这一点并优化了字节码。

关于性能,是否值得在全局范围内声明一个常量值?性能提升是否证明将常量值移到远离程序员使用和读取的位置是合理的?

【问题讨论】:

  • 为什么必须从内存中查找一个值而不是在字节码的方法主体中拥有文字权才能提高性能?
  • This question 你可能会感兴趣。

标签: java performance


【解决方案1】:

Java 编译器用它的值替换所有出现的这个静态 final 字段;局部变量是运行时堆栈帧的一部分。更全面的解释见The Java® Virtual Machine Specification

我认为你的情况在性能上没有任何差异。

【讨论】:

  • 哇!围绕这个问题充满热情!谢谢大家的回复。这个问题源于我与一位同事的对话,他/她试图让我相信全局静态变量比本地变量更易于维护且性能更好。在阅读了回复并执行了一些本地测试之后,我认为将变量保持在靠近使用位置的位置更好。似乎没有显着的性能影响,它更容易找到,并且与代码保持在上下文中。感谢大家。感谢您的宝贵时间。
【解决方案2】:

首先,这种微优化并不是您真正应该关注的细节。如果有的话,在您的代码中涉及更多的部分会在性能方面获得更多的胜利。

这种微优化不会给您带来太多好处,而且您可能会牺牲可读性来获得微不足道的性能提升。

您的代码没有任何地方存在巨大的性能瓶颈,因此如果您进行任何微优化,我预计不会有任何重大的性能提升。

对于您的主要问题,静态最终变量背后的想法是双重的:

  • 您避免使用magic numbers,从而明确您的意图。
  • 如果您的值需要更改,您可以在一处更改,而不是多处更改。

我认为,如果其他类没有使用它,那么它不需要是public。我仍然建议它是一个类变量,因此它具有示例 1 的样式,但声明为 private static final int onlyUsedByMethodFoo = 1;

【讨论】:

    【解决方案3】:

    对于这种情况,性能(至少对于原始类型)不是问题。更重要的是“代码质量”,即代码的一致性、可读性和干净程度。 所以,如果你想要一个特定于上下文的变量,在它真正属于的地方定义它,不要把全局上下文弄乱

    【讨论】:

      【解决方案4】:

      过早进行优化不是一个好习惯。专注于设计,好的设计易于扩展和维护。如果你有一个好的设计和代码,识别性能问题(如果有的话)不会很麻烦并且可以处理。再次 - 永远不要做未成熟的优化。此外,现在,编译器被调整为生成优化的字节码。

      【讨论】:

        【解决方案5】:

        特定 Java 实现/版本的 JIT 编译器可能会根据它可以推断出的关于代码的各种内容来选择专门优化。但是,一般来说,优化 static final 类成员比优化 final 方法变量更容易。

        所讨论的变量是一个原始变量(int)这一事实可能会改变一些事情;如果它是一个引用类型,它会更难优化。因为它不是一个对象,所以你不能用引用相等或类似的东西做任何技巧;考虑这个例子并将其与您的final int 进行比较:

        void foo() {
        final Object o = new SomeObject();
        }
        

        我认为,在这种情况下,final 对性能没有任何帮助根本,因为如果您在各个方法调用之间比较 o,语义的期望是,它应该是一个不同的对象,即它不会 == 来自先前方法调用的 o。但是如果你让它成为一个静态的 final 类成员,你就真正拥有了一个单例对象。

        我不清楚 JIT 是否必须优化或不优化方法中的 finalprimitives,因为可以想象,它可以将其优化为仅将其存储在一个地方,但是很明显,对于引用类型,类成员在内存/CPU 方面的开销将(略微)降低。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2019-08-21
          • 1970-01-01
          • 1970-01-01
          • 2011-03-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多