【问题标题】:Does defining variables as "locally" as possible make the implementation faster?尽可能将变量定义为“本地”是否会使实现更快?
【发布时间】:2012-04-06 22:03:05
【问题描述】:

在编程时,我经常会遇到以下场景(在代码中描述)。我在要使用的块中定义变量。

    int maximumLengthOfToken = 0;

    while(fileScanner.hasNextLine())
    {
       String line; // definition
       line = fileScanner.nextLine();

       Scanner lineScanner; // definition
       lineScanner = new Scanner(line);

       String token = lineScanner.next(); // definition and assignment
       if(stringToMatch.endsWith(token))
        {
                 if(token.length() >= maximumLengthOfToken )
                  {
                     maximumLengthOfToken = token.length();  
                     builder.append(line);
                     builder.append("\n\n\n");
                  }
        }
    }
    fileScanner.close();

但是,有时,为了“整洁”,也因为我来自 C 背景,我喜欢在顶部定义所有变量,而不管它们在哪里使用。所以我做了以下 -

    int maximumLengthOfToken = 0;
    String line; // definition
    Scanner lineScanner; // definition
    String token; // definition

    while(fileScanner.hasNextLine())
    {
       line = fileScanner.nextLine();
       lineScanner = new Scanner(line);

       token = lineScanner.next(); // definition

               if(stringToMatch.endsWith(token))
                {
                 if(token.length() >= maximumLengthOfToken )
                  {
                     maximumLengthOfToken = token.length();  
                     builder.append(line);
                     builder.append("\n\n\n");
                  }
        }
    }
    fileScanner.close();

“啊!看起来很整洁”,我想。

但是,这对代码的性能有什么影响吗?第一种风格会导致更快的代码执行还是第二种风格?另外,在这种情况下,约定是什么?我相信这是第一种风格。

【问题讨论】:

  • 编译器可能会观察到它们是等价的,从而将它们编译为相同的字节码。
  • 假设编译器没有考虑语义等价性并因此没有优化第一段代码,垃圾收集是否会在此处产生速度差异?
  • 您应该考虑在变量第一次使用的地方声明它们。它使代码更容易被其他人推理。没有什么比在顶部看到一堆变量声明并不得不在心里跟踪它们更糟糕的了。另见programmers.stackexchange.com/q/56585

标签: java performance coding-style


【解决方案1】:

没有。不会有性能差异。

如果您对此表示怀疑,请问问自己,“如果我的变量在 2000 字节之外,计算机查找我的变量会比在 200 字节或 20 字节之外花费更长的时间吗?”答案应该是否定的。

可能产生影响的唯一情况是,如果您的变量在使用之前从处理器缓存(see locality) 中退出,在这种情况下,将变量移到更靠近使用它的位置可能会提高速度。但是在变量和它的使用之间需要大量的代码才能实现。

编译器也有可能将你的方法编译成相同的字节码。总之,我觉得你不用担心。

【讨论】:

  • +1 用于链接位置参考和优化编译器的(隐式)提及。
【解决方案2】:

正如其他人所说,没有显着的性能差异。

您希望在将变量声明放在方法顶部和将它们放在使用它们的位置之间进行选择。不要强迫自己做出这样的选择。你可以两者兼得——通过使你的方法非常简短。当您发现自己面临这种选择时,请将其视为您的代码告诉您:“您的方法太长了。”

更短的方法更容易编写、更容易测试、更容易调试、更容易维护。如果您没有(比如说)10 行以上的方法,那么您将永远不会遇到这个问题 - 而且您将拥有更好的组织代码。

【讨论】:

    【解决方案3】:

    这可能对代码的性能没有任何影响——我希望生成的字节码是相同的——但第一个版本通常被认为更易于维护和可读。

    【讨论】:

      【解决方案4】:

      在一般情况下,可能会有轻微的(有时甚至是巨大的)差异,但在 Java 的情况下,标准编译器链很可能不会。

      编译器可能会有所不同的是,“varA”定义在一个范围内,“varB”定义在不相交的范围内。编译器可能会观察到范围是不相交的,并将相同的堆栈槽分配给两者,这非常非常轻微地提高了解释器的性能。但是,如果它不够聪明,无法弄清楚发生了什么,这种技术可能会在 JITC 中导致更糟糕的优化。

      【讨论】:

        【解决方案5】:

        由于在现代 Java 实现中使用了运行时优化,您应该不会看到太大的差异。因此,您应该主要关注清晰度和易于维护。

        也就是说,有几个充分的理由将变量声明为尽可能靠近使用位置:

        • 它更易于阅读,尤其是对于非常短暂的(例如临时)变量。读者可以立即看到变量的类型,而无需向上滚动到方法的开头。

        • 通过尽可能地限制变量的范围,您可以减少意外错误的可能性,例如:重复使用循环计数器。

        • 当变量的范围尽可能有限时,一些优化(例如转义分析)可能会执行得更好。

        作为旁注,我同时使用 C 和 Java 编程,并且 有时很难从一个上下文切换到另一个。但是,在 Java 中使用 C 风格的约定(反之亦然)并不是一个好主意。 C 约定是由 Java 根本没有的限制决定的 - 使用它们只会使您的代码更难被其他人阅读。

        【讨论】:

          【解决方案6】:

          关于变量范围的最大“性能”差异将在垃圾收集中。在本地声明变量可能会允许 GC 更快地收集未使用的变量。

          【讨论】:

            猜你喜欢
            • 2021-12-28
            • 2012-03-11
            • 1970-01-01
            • 2021-06-29
            • 2015-02-22
            • 1970-01-01
            • 2014-08-30
            • 2013-05-18
            • 1970-01-01
            相关资源
            最近更新 更多