16

我今天正在教授一门入门编程课程,并且正在学习一些涉及 Java 变量赋值的简单代码。代码的重点不是炫耀任何特别令人兴奋的东西,而是主要是为了确保学生理解变量赋值语句。

我在板上有以下方法,一次一行地跟踪它:

private void simpleMethod() {
    int myInt = 137;
    myInt = 42;
    myInt = myInt + 1;

    /* ... code using myInt ... */
}

一个学生问我myInt在程序运行时是否真的会保存值 137 和 42,或者它是否会直接跳转到保存 43。我告诉学生代码将依次执行每一行,所以变量实际上会保存这些中间值。

不过,老实说,我不确定字节码javac会发出什么(完全忽略了 JVM 所做的优化)。(或任何 Java 编译器)是否javac合法允许优化愚蠢的赋值语句,而直接初始化myInt为 43?

根据javap,在我的系统上,上面用编译的代码javac产生

   0: sipush        137
   3: istore_1      
   4: bipush        42
   6: istore_1      
   7: iload_1       
   8: iconst_1      
   9: iadd          
  10: istore_1      
  11: return        

所以这里没有优化。不过,我的问题是优化这个是否合法,所以这并不能解决任何问题。

4

4 回答 4

8

JLS 仅指定程序产生的可观察行为的契约。由于myInt是本地的,优化确实可以在编译时进行优化,因为这会产生与规范一致的行为,并且规范中没有任何内容说它是不允许的(至少,不是我发现的!)。规范的第 1 章明确规定了规范的可观察性:This document fully specifies the (apparent) order of evaluation of expressions.... 由于通过恒定折叠到myInt = 43,表观行为没有改变,因此优化将与 JLS 一致。

事实上,Java 应用程序的编译目标甚至没有在 JLS 中指定。第 1 章说 Java 应用程序“通常”编译为 JVM 规范(一个单独的文档)中指定的字节码,但并不要求它们这样做。有些语句必须在编译时进行优化,但不是myInt这样。即使myInt是一个领域,我认为优化是允许的;不同的行为仍然是有效的行为,即使myInt是易变的(因为它代表一种有效的事件顺序)。

所以,简短的回答,我认为你的学生是正确的;将其优化为myInt = 43. 也就是说,javac通常在优化方面做的很少——几乎没有。优化几乎都是在 JIT 中完成的。

于 2013-01-15T07:59:57.117 回答
5

我相信 Java 编译器可以进行任何可以在编译时静态确定的常量折叠。

所以是的,这可以通过javac.

但是javac 不需要进行这种优化,因为 JVM JIT 编译器几乎肯定会为您做同样的优化。从这个角度来看,Java -> Bytecode 编译器是否进行这种优化可能与在运行时执行的实际本机代码的影响无关。

于 2013-01-15T07:06:14.017 回答
0

所以这里没有优化。

鉴于 Java 使用动态编译,这应该不足为奇。

JVM 在运行时优化了几乎所有的代码,这意味着无论您使用 1996 年为 Java 1.0 编译的代码还是 Scala 或 JRuby、JGo 等,您都可以从针对特定 CPU 模型的本机代码的优化中获得全部好处。

出于这个原因,许多语言都有 JVM 实现,因此它们不需要能够为 JVM 运行的所有平台生成最佳代码。

于 2013-01-15T08:09:31.920 回答
0

虽然这是真的,但我的问题是编译器是否在法律上被允许进行这种优化

通过传统的数据流分析(流/传输函数、in-sets、out-sets、gen-sets、kill-sets 等),特别是一些路径转发数据流,也就是到达定义(或 use-def 链)。 .. 是的。本质上,优化器可以将变量的每次使用与到达它的定义联系起来。

在这种情况下,优化器可以确定 myInt (=137) 的初始定义永远不会达到它的用途,而另一个定义 (=42 1 ) 确实会达到它的用途,因为它永远不会在该定义的任何(某些)路径上重新定义到它的用途。

参考:

  • 龙书 1ed (1986) 第 10 章
  • 龙书 2ed (2007) 第 9 章(特别是 9.2)

1 - 我在教学代码中一直使用 42。我敢打赌我们都这样做。

于 2013-01-15T15:58:59.067 回答