【问题标题】:Java Compiler executes return before if statementJava 编译器在 if 语句之前执行 return
【发布时间】:2020-01-20 04:13:46
【问题描述】:

java compiler在优化时有没有可能在java中忽略if statement

我们有两个环境 [A 和 B 相同],并且在两个环境中部署了相同的代码。 该代码有一种方法,其代码如下:

private LocaleCodeValue getDefaultLocaleCodeValue(String code) {
String value = code;
if (code.contains("_")) value = code.substring(0, code.lastIndexOf("_"));
return new LocaleCodeValue(code, value);
}

这应该适用于两种环境。

但是,在环境 B 上,有时会忽略 if 语句并在条件为真时直接返回对象。为了调试,我们执行了将导致条件为真的操作。它适用于anv A,但不适用于B(有时)。但我们 100 % 确定条件始终为真。 经过多天的调试,我们得出一个结论,即 JIT 编译器可能正在优化代码并可能忽略 if 语句。

所以我们把代码改成下面这样:

private LocaleCodeValue getDefaultLocaleCodeValue(String code) {
    String value = code;
    if (code.contains("_")) {
     value = code.substring(0, code.lastIndexOf("_"));
     return new LocaleCodeValue(code, value);
    }
    return new LocaleCodeValue(code, value);
    }

现在代码按预期工作了。

我同意这个问题很难重现,但是我很好奇有人遇到过这样的问题吗?或者有没有可能是java编译器搞砸了这个?

Java Image : image: openjdk:10-jdk-slim

【问题讨论】:

  • 可能会抛出异常
  • 要么你的假设是错误的,并且在环境 B 上,当你认为它是,条件是 not true,或者你在编译器中发现了一个错误。这两个实现应该是 100% 等效的。鉴于在广泛部署的应用程序中发现这么大的错误似乎有些牵强,我想问题只是当您期望它为真时条件为假。如果您需要更多帮助,请提供我们可以实际运行和测试的示例代码。
  • 我们无法根据您显示的内容进行猜测。显示实际代码,包括其上下文(在 try 块中?)。条件可能会引发异常,如果返回位于 finally 块中或异常被忽略,则可能会发生这种情况。
  • 嗯,可能在某些情况下可能会发生这种情况(至少因为 JIT 是一个可能包含错误的软件),但我首先要寻找一个我的方程式中的错误。您能否详细说明您实际在做什么(最好是minimal reproducible example)以及您正在使用的确切 Jave 版本?
  • @GiacomoAlzetta 我同意你的观点,但我们 100% 确定条件始终正确。我们调试了将近 5 天。请相信。

标签: java compiler-optimization jit


【解决方案1】:

有没有可能是java编译器搞砸了这个?

理论上是的。这在数学上是可能的。

在实践中......您更有可能是遗漏了某些东西,或者您对 Java 行为的某些方面存在误解。 (例如,是什么让程序线程安全。)

Java 被数以百万计的程序员使用。确实会发现错误,但是在某些“看起来很普通”的代码中,任何给定的意外/不理解行为是由于编译器错误造成的可能性很小。

(此外,除非您可以以可重现的测试用例的形式提供假定的编译器错误的证据:

  1. 您将无法报告/修复它,并且
  2. 您将没有任何逻辑基础来相信您的解决方法实际上正在解决问题。 (它可能只是降低它的概率,或者将它移动到其他地方。)

该代码有一种方法,其代码如下:

(那是真实的代码吗?还是只是“喜欢”它?如果只是“喜欢”它,它与真实代码有什么区别?)

private LocaleCodeValue getDefaultLocaleCodeValue(String code) {
    String value = code;
    if (code.contains("_")) 
        value = code.substring(0, code.lastIndexOf("_"));
    return new LocaleCodeValue(code, value);
}

可能性 #0。问题是这个方法的输入或输出不是你想象的那样。 (请注意,如果应用程序是多线程的,则使用调试器或添加跟踪或日志记录可能会改变应用程序的行为。以可能隐藏实际证据的方式。)

可能性 #1。问题出在LocaleCodeValue 构造函数中。

可能性 #2。 Homoglyphs:在某些情况下,您会得到一些看起来类似于'_' 字符的字符,但实际上并非如此。

可能性 #3。代码库中的其他地方是一些使用讨厌的反射来改变String 值的代码,它恰好改变了code 的值。在调用此方法期间它甚至可能不会这样做......如果它发生在不同的线程上。

可能性 #4。在代码库的某个地方,一些有缺陷的本机代码被调用,这是在践踏某些东西。

可能性 #5。硬件错误。

可能性 #6。您正在运行的代码与您正在查看的源代码不匹配;例如您的构建或部署过程有问题。

可能性 #7。您向我们展示的内容与真实代码之间存在一些细微但重要的区别。

我的赌注是#0、#6 或#7(除了你刚才说不是#7)。


如果尽管有所有其他可能性,您仍然认为自己有编译器错误,那么接下来的步骤是检查字节码是否有错误,然后让 JVM 转储 JIT 编译的本机代码并进行检查。此外,您需要创建一个(例如)Oracle 的 Java 工程师可以处理的可重现示例。

【讨论】:

  • 这是准确的代码。是的,这完全是关于might have happened,因为没有字符串点说这是编译器中的一个错误。这是有经验的,因此问了一个问题,如果有人遇到过这样的问题。顺便说一句,感谢您的帮助:)
猜你喜欢
  • 2015-02-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-28
  • 2017-02-05
相关资源
最近更新 更多