哪个循环有更好的性能?为什么?

Viv*_*ira 50 java string performance garbage-collection

String s = "";
for(i=0;i<....){
    s = some Assignment;
}
Run Code Online (Sandbox Code Playgroud)

要么

for(i=0;i<..){
    String s = some Assignment;
}
Run Code Online (Sandbox Code Playgroud)

我不需要再次在循环外使用's'了.第一个选项可能更好,因为每次都不会初始化新的String.然而,第二个将导致变量的范围限于循环本身.

编辑:回应Milhous的回答.将String分配给循环中的常量是没有意义的吗?不,这里'一些分配'意味着从迭代的列表中获得的变化值.

此外,问题不是因为我担心内存管理.只是想知道哪个更好.

eri*_*son 108

有限的范围是最好的

使用您的第二个选项:

for ( ... ) {
  String s = ...;
}
Run Code Online (Sandbox Code Playgroud)

范围不影响性能

如果你反编译每个编译的代码(使用JDK的javap工具),你会发现循环在两种情况下编译成完全相同的JVM指令.另请注意,Brian R. Bondy的 "选项#3"与选项#1相同.使用更紧密的范围时,不会在堆栈中添加或删除任何额外内容,并且在两种情况下都在堆栈上使用相同的数据.

避免过早初始化

这两种情况的唯一区别在于,在第一个示例中,变量s被不必要地初始化.这是与变量声明的位置不同的问题.这会添加两条浪费的指令(加载字符串常量并将其存储在堆栈帧插槽中).一个好的静态分析工具会警告你,你永远不会读取你赋予的值s,而一个好的JIT编译器可能会在运行时忽略它.

你可以简单地通过使用一个空声明来解决这个问题(即String s;),但这被认为是不好的做法,并且下面讨论了另一个副作用.

通常将伪造的值null分配给变量只是为了避免编译器错误,即读取变量而不进行初始化.此错误可以视为变量作用域太大,并且在需要接收有效值之前声明它.空声明强制您考虑每个代码路径; 不要通过指定虚假值来忽略这个有价值的警告.

保留堆栈槽

如上所述,虽然JVM指令在两种情况下都是相同的,但是有一个微妙的副作用,使得在JVM级别最好使用尽可能最有限的范围.这在方法的"局部变量表"中可见.考虑如果你有多个循环会发生什么,变量在不必要的大范围内声明:

void x(String[] strings, Integer[] integers) {
  String s;
  for (int i = 0; i < strings.length; ++i) {
    s = strings[0];
    ...
  }
  Integer n;
  for (int i = 0; i < integers.length; ++i) {
    n = integers[i];
    ...
  }
}
Run Code Online (Sandbox Code Playgroud)

变量sn可以各自循环内部声明,但由于他们都没有,编译器使用堆栈帧两个"插槽".如果它们在循环内声明,则编译器可以重用相同的槽,使堆栈帧更小.

真正重要的是什么

但是,大多数这些问题并不重要.一个好的JIT编译器将会看到无法读取您浪费分配的初始值,并优化分配.在这里或那里保存一个插槽不会决定你的应用程序.

重要的是使您的代码可读且易于维护,在这方面,使用有限的范围显然更好.变量具有的范围越小,就越容易理解它的使用方式以及对代码的任何更改会产生什么影响.


Est*_*aya 22

理论上讲,在循环中声明字符串是浪费资源.但实际上,您提供的两个片段都将编译为相同的代码(循环外的声明).

因此,如果您的编译器进行了任何数量的优化,那么没有区别.

  • 它是什么理论,它告诉你*声明*变量会浪费资源? (5认同)

Gre*_*ill 17

一般来说,我会选择第二个,因为's'变量的范围仅限于循环.优点:

  • 这对程序员来说更好,因为你不必担心在函数后面的某个地方再次使用's'
  • 这对编译器来说更好,因为变量的范围较小,因此可以进行更多的分析和优化
  • 这对于未来的读者来说更好,因为他们不会想知道为什么's'变量在循环之外被声明,如果它以后从未使用过


GHa*_*Had 6

如果你想加速循环,我更喜欢在计数器旁边声明一个max变量,这样就不需要重复查找condidtion了:

代替

for (int i = 0; i < array.length; i++) {
  Object next = array[i];
}
Run Code Online (Sandbox Code Playgroud)

我更喜欢

for (int i = 0, max = array.lenth; i < max; i++) {
  Object next = array[i];
}
Run Code Online (Sandbox Code Playgroud)

任何其他应该考虑的事情都已经提到了,所以只需要我的两分钱(见erickons帖子)

格雷茨,GHad