gpt4 book ai didi

java - Java 编译器是否优化了循环局部变量的创建?

转载 作者:行者123 更新时间:2023-12-01 17:41:33 25 4
gpt4 key购买 nike

让我们看一下这个例子:

String var;
while (...) {
var = ...
// do stuff
}

在本例中,我们创建对 String 的引用对象并在循环的每次迭代中为其分配不同的对象。

现在,在另一个例子中:

while (...) {
String var = ...
// do stuff
}

如果我们假设编译器很幼稚,它只会分配对 String 的引用。堆栈上的对象每次迭代

或者会吗?这就是我的问题 - (a?) Java 编译器是否执行此优化?我总是将对象声明保留在尽可能广泛的范围内,因为我担心这一点,但如果编译器已经这样做了,我的鞋子上就少了一颗鹅卵石。

提前谢谢您!

最佳答案

it'll just allocate a reference to a String object on stack every iteration.

事情不是这样的。堆栈上的变量,即参数和局部变量,在方法入口处分配(保留)。

例如如果你有这样的代码:

static void foo() {
String s;
for (int i = 0; i < 5; i++) {
int j = i;
s = String.valueOf(j);
bar(s);
}
for (int j = 0; j < 5; j++) {
int k = j;
s = String.valueOf(k);
bar(s);
}
}
static void bar(String s) {
}

对于该代码,将在堆栈上分配 3 个槽1:

  • s将位于槽 0 中,并在整个方法中使用慢速

  • i在第一个循环期间将位于槽 1 中。

  • j将在第一个循环的主体持续时间内位于槽 2 中。

  • 另一个 j在第二个循环期间将位于插槽 1 中。

  • k将位于插槽 2 中,持续第二个循环的主体

如您所见,槽 1 和槽 2 被重用,但在方法执行期间没有进行“分配”。仅在方法开始时分配/反转的内存。

1) 一个槽为 4 字节/32 位,即 int 的大小或引用(带有压缩的 Oops)。

如果使用 javac -g Test.java 进行编译并用 javap -v -c Test.class 进行拆卸,您将得到(Java 8 的输出):

  static void foo();
descriptor: ()V
flags: ACC_STATIC
Code:
stack=2, locals=3, args_size=0
0: iconst_0
1: istore_1
2: iload_1
3: iconst_5
4: if_icmpge 24
7: iload_1
8: istore_2
9: iload_2
10: invokestatic #2 // Method java/lang/String.valueOf:(I)Ljava/lang/String;
13: astore_0
14: aload_0
15: invokestatic #3 // Method bar:(Ljava/lang/String;)V
18: iinc 1, 1
21: goto 2
24: iconst_0
25: istore_1
26: iload_1
27: iconst_5
28: if_icmpge 48
31: iload_1
32: istore_2
33: iload_2
34: invokestatic #2 // Method java/lang/String.valueOf:(I)Ljava/lang/String;
37: astore_0
38: aload_0
39: invokestatic #3 // Method bar:(Ljava/lang/String;)V
42: iinc 1, 1
45: goto 26
48: return
      LocalVariableTable:
Start Length Slot Name Signature
9 9 2 j I
14 10 0 s Ljava/lang/String;
2 22 1 i I
33 9 2 k I
38 10 0 s Ljava/lang/String;
26 22 1 j I

如您所见,行 stack=2, locals=3, args_size=0显示它将为局部变量保留 3 个槽位。 LocalVariableTable底部显示哪个局部变量在哪个字节码指令(范围)的持续时间内使用哪个槽。

移动s的声明循环内部将重新排列变量分配给槽的顺序,即它们使用哪些槽,并更改 s 范围的长度,但就是这样。

static void foo() {
for (int i = 0; i < 5; i++) {
int j = i;
String s = String.valueOf(j);
bar(s);
}
for (int j = 0; j < 5; j++) {
int k = j;
String s = String.valueOf(k);
bar(s);
}
}
      LocalVariableTable:
Start Length Slot Name Signature
9 9 1 j I
14 4 2 s Ljava/lang/String;
2 22 0 i I
33 9 1 k I
38 4 2 s Ljava/lang/String;
26 22 0 j I

关于java - Java 编译器是否优化了循环局部变量的创建?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60481374/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com