【问题标题】:For a local variable declared in a loop is memory allocated each iteration?对于在循环中声明的局部变量,每次迭代都会分配内存吗?
【发布时间】:2021-10-13 13:01:31
【问题描述】:

我很惊讶地在 Cay Horstmann 的 Java 9 书中读到,每次都在增强的 for 循环中将内存分配给临时对象:

“每次迭代都会创建一个新变量 arg”(第 3 章,第 126 页)

for(String arg:args) {
...
}

我一直认为编译器会在进入循环之前为循环中的局部变量分配空间,以优化性能。

为什么每次都要创建变量?

before 是在 C 的上下文中提出的这个问题,但不是在 Java 中提出的。我一般要求一个循环,而不仅仅是这种情况。

【问题讨论】:

  • 每次都会创建一个新变量(Java 中的引用),因为它在每次迭代中指向不同的值。但是内存 - 可能是/可能不是 - 了解字符串文字池?
  • @Kris:这与字符串池完全无关。 arg 引用的任何字符串都已经存在于args 中,因此无论如何都不会创建新的字符串对象。
  • @JoachimSauer 你是对的,问题标题包含内存分配,所以我提到了。
  • 局部变量的内存不是以经典方式“分配”的,而是JVM将为给定方法的所有局部变量保留足够的内存(这在编译时是已知的)。虽然arg 在每次迭代中都可以被视为一个新变量(具有新值),但它几乎肯定会重复使用相同的插槽(即内存中的相同位置)。

标签: java


【解决方案1】:
for (String s : ...) { }
double x;
for (int i : ...) {
   long n; ...
}
double y;

对于上述情况,编译器将在调用堆栈上声明 5 个变量槽,它们可以重叠(x 与 s 共享内存)。所需的堆栈大小已添加到方法中,因此可以检查 stackoverflow。

只有任何赋值,如对象创建,在循环内重复。

不过,这是需要的。初学者的错误是:

List<A> list = new ArrayList<>();
A obj = new A(); // *** ERROR ***
for (...) {
    obj.name = ...;
    list.add(obj);
}

用相同的对象实例填充列表,其字段属于最后一个循环步骤。

n 的重复创建未完成。将声明放在 for 循环之外的调用肯定不是优化 - 相反:堆栈上的变量槽保留在循环之后。

【讨论】:

  • “当然,将声明放在 for 循环之外的调用绝对没有优化 - 相反。”。请澄清 - 这句话对我来说不连贯。
  • 外部编译器必须为变量n分配一个槽。在循环内部,当循环范围完成时,可以回收插槽。 y 的堆栈地址可以紧跟在 x 之后。节省堆栈空间。
  • 你能编辑你的答案吗?请编辑这句话“当然绝对没有优化将声明放在 for 循环之外的调用 - 相反。”
  • @likejudo 这确实不是干净的英语,甚至不是很连贯。感谢您有机会更正它。
猜你喜欢
  • 1970-01-01
  • 2014-12-01
  • 2011-08-16
  • 2011-12-20
  • 1970-01-01
  • 2014-01-01
  • 2020-08-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多