【问题标题】:How bad is declaring arrays inside a for loop in Java?在 Java 的 for 循环中声明数组有多糟糕?
【发布时间】:2011-09-01 22:51:37
【问题描述】:

我来自 C 背景,所以我承认在用 Java 编写时我仍然在为放弃内存管理而苦苦挣扎。这是一个已经出现过几次的问题,我很想详细说明一下。以下是编写相同例程的两种方法,唯一的区别是声明 double[] array 的时间:

代码示例 1

double[] array;
for (int i=0; i<n; ++i) {
    array = calculateSomethingAndReturnAnArray(i);
    if (someFunctionOnArrays(array)) {
        // DO ONE THING
    } else {
        // DO SOME OTHER THING
    }
}

代码示例 2

for (int i=0; i<n; ++i) {
    double[] array = calculateSomethingAndReturnAnArray(i);
    if (someFunctionOnArrays(array)) {
        // DO ONE THING
    } else {
        // DO SOME OTHER THING
    }
}

这里,private double[] calculateSomethingAndReturnAnArray(int i) 总是返回一个相同长度的数组。我对 代码示例 2 有强烈的反感,因为它会为每次迭代创建一个新数组,而它可能只是覆盖现有数组。但是,我认为这可能是我应该坐下来让 Java 为我处理这种情况的时候之一。

选择其中一种方法而不是另一种方法的原因是什么,或者它们在 Java 中是否真的相同?

【问题讨论】:

  • 您在这两种情况下都创建了一个新数组。您只是在第一个样本中声明数组一次(其存储空间为 32 位,因为它只是一个参考)。但大概calculateSomethingAndReturnAnArray 总是在实例化一个新数组,这才是真正的成本所在。
  • @Kirk...介意把这个拿出来作为答案吗?
  • 嗯,@Mark 的回答更好。 ;)
  • @Kirk:两者都非常有帮助。谢谢。

标签: java memory-management


【解决方案1】:

这里的数组没有什么特别的,因为你不是为数组分配,你只是创建一个新变量,它相当于:

Object foo;
for(...){
    foo = func(...);
}

如果您在循环之外创建变量,则该变量(将保存它所指事物的位置)只会被分配一次,如果您在循环内创建变量,该变量可能会在每次迭代中重新分配,但我的猜测是编译器或 JIT 将在优化步骤中修复它。

我认为这是一种微优化,如果您在这段代码中遇到问题,如果您没有遇到问题,您应该根据测量结果而不是仅根据规范做出决策使用这段代码,您应该做语义正确的事情并在有意义的范围内声明变量。

另请参阅similar question about best practices

【讨论】:

  • 感谢您的解释和参考。
【解决方案2】:

local 变量的声明没有初始化表达式将不起作用。当变量被初始化时,工作就发生了。

因此,以下在语义和性能方面是相同的:

double[] array;
for (int i=0; i<n; ++i) {
    array = calculateSomethingAndReturnAnArray(i);
    // ...
}

for (int i=0; i<n; ++i) {
    double[] array = calculateSomethingAndReturnAnArray(i);
    // ...
}

(你甚至不能怀疑第一种情况允许在循环结束后使用array。为了合法,array 在循环后必须有一个确定的值,但它没有' t 除非您在声明中添加初始化程序;例如 double[] array = null;)


详细说明@Mark Elliot 关于微优化的观点:

  • 这实际上是一种优化的尝试,而不是真正的优化,因为(正如我所指出的)它应该没有效果。

  • 即使 Java 编译器实际上为 double[] array; 生成了一些重要的可执行代码,与循环体和应用程序的总执行时间相比,执行时间也可能微不足道作为一个整体。因此,这很可能是毫无意义的优化。

  • 即使这是一个值得的优化,你也必须考虑到你已经针对特定的目标平台进行了优化;即硬件和 JVM 版本的特定组合。像这样的微优化在其他平台上可能不是最优的,理论上可能是反优化。

总之,如果您在编写 Java 代码时专注于此类事情,您很可能会浪费时间。如果您的应用程序关注性能,请关注 MACRO 级别的性能;例如诸如算法复杂性、良好的数据库/查询设计、网络交互模式等等。

【讨论】:

    【解决方案3】:

    两者都为每次迭代创建一个新数组。它们具有相同的语义。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-02-16
      • 2011-05-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-24
      相关资源
      最近更新 更多