【问题标题】:Final variables in class file format类文件格式的最终​​变量
【发布时间】:2016-10-28 23:30:17
【问题描述】:

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

Here,在类文件格式文档中,他们提到了 final 关键字,但仅限于与 final 块final class 一起使用的情况。
最终变量没有任何意义。

【问题讨论】:

    标签: java performance bytecode final jit


    【解决方案1】:

    不,类文件中没有编码这样的信息。

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

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

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

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

    编译器将优化代码A,就好像x 始终是1,而代码B 就好像x 始终是2

    【讨论】:

    • 请注意,即使MethodParameters 属性告诉特定方法参数变量是final,也不能保证特定局部变量索引在整个方法中与该参数相关联。 Afaik,对于javac 生成的代码,就是这种情况,但原则上,如果以后不访问参数,索引可以被重用于不同的变量。最大的障碍是final for-each 循环变量,它们在语义上是final,但在字节码级别的每次循环迭代中都会被覆盖……
    【解决方案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,因此,对于上面的示例,优化器会将代码视为必须常量,@987654335 @ 和 c₂:=5,并且根据后续代码的位置,可以确定使用哪个常量,换句话说,它不仅仅是拥有“有效最终”变量,即使更改变量也可以视为多个 final 变量(在没有线程同步的情况下,即使是堆变量的改变也可能暂时得到类似的处理)。

    【讨论】:

      猜你喜欢
      • 2014-12-07
      • 1970-01-01
      • 2015-07-06
      • 2011-09-27
      • 2018-09-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-07-29
      相关资源
      最近更新 更多