类文件格式的最终​​变量

时间:2016-10-15 08:19:40

标签: java performance bytecode final jit

文件格式是否支持 final 关键字,以便将其与变量一起使用?
或者它只是从代码中推断出变量的有效终结性,而JIT编译器是否基于它执行优化?

Here,在类文件格式文档中,他们提到了final关键字,但仅限于将其与 final block final class 一起使用。<登记/> 最终变量没有任何内容。

2 个答案:

答案 0 :(得分:7)

不,在类文件中没有编码此类信息。

您可以通过使用final局部变量并且没有final编译源文件来轻松验证这一点 - 结果类将是相同的。

但是,Java 8添加了MethodParameters属性,该属性记录有关方法参数的名称和访问标志的信息。这意味着,您可以检查方法参数是否为final

即时编译器不需要了解final本地人 - 他们可以轻松确定任何表达式的实际范围。即使变量不是最终的,例如

    int x = 1;
    // ... code A ...

    x = 2;
    // ... code B ...

编译器会优化代码A,就好像x始终是1一样,代码B就好像x始终是2 }。

答案 1 :(得分:2)

也许我们应该首先重新考虑“变量”一词。在大多数情况下,术语“变量”包括局部变量,static和非static字段,甚至通常包括数组元素(例如,在内存模型中)。由于数组元素不支持final,因此只能为字段和局部变量给出答案。

对于字段, ACC_FINAL标志,用于指示字段是否为final。它有不同的后果。 static final字段只能在类初始值设定项中写入,而final实例字段不仅可以在构造函数中写入,还可以通过带有访问覆盖的反射。在优化时,JVM试图从实例字段的final性质中获益,必须注意检测反射修改。

对于局部变量,没有final标志,事实上,根本没有正式的声明。在Java字节代码中,局部变量只是stack frame中的索引,可以随意重用而不会预感。因此,对局部变量索引的写入可以是变量的变化,也可以是对新变量的相同索引的重用,例如, { int x=4; } { int y=5; }可能会编译为与{ int x=4; x=5; }相同的字节代码。

对于JVM的优化器,无论如何都没关系,因为它会将局部变量的操作转换为SSA form,因此,通过上面的示例,优化器会将代码视为必须为常量, c₁:=4c₂:=5,并且根据后续代码的位置,可以确定使用哪个常量,换句话说,它不仅仅具有“有效最终”变量,甚至可以处理变更变量像多个final变量一样(在没有线程同步的情况下,即使对堆变量的更改也可能暂时得到类似的处理)。