JMH - 为啥 JIT 不能消除我的死代码

Posted

技术标签:

【中文标题】JMH - 为啥 JIT 不能消除我的死代码【英文标题】:JMH - why JIT does not eliminate my dead-codeJMH - 为什么 JIT 不能消除我的死代码 【发布时间】:2019-01-14 15:58:56 【问题描述】:

我写了两个基准来证明 JIT 可能会成为编写精细基准的问题(请跳过我在这里不使用@State):

@Fork(value = 1)
@Warmup(iterations = 2, time = 10)
@Measurement(iterations = 3, time = 2)
@BenchmarkMode(Mode.AverageTime)
public class DeadCodeTraps 

    @Benchmark
    @OutputTimeUnit(TimeUnit.MICROSECONDS)
    public static void summaryStatistics_standardDeviationForFourNumbers() 
        final SummaryStatistics summaryStatistics = new SummaryStatistics();
        summaryStatistics.addValue(10.0);
        summaryStatistics.addValue(20.0);
        summaryStatistics.addValue(30.0);
        summaryStatistics.addValue(40.0);
        summaryStatistics.getStandardDeviation();
    

    @Benchmark
    @OutputTimeUnit(TimeUnit.MICROSECONDS)
    public static void summaryStatistics_standardDeviationForTenNumbers() 
        final SummaryStatistics summaryStatistics = new SummaryStatistics();
        summaryStatistics.addValue(10.0);
        summaryStatistics.addValue(20.0);
        summaryStatistics.addValue(30.0);
        summaryStatistics.addValue(40.0);
        summaryStatistics.addValue(50.0);
        summaryStatistics.addValue(60.0);
        summaryStatistics.addValue(70.0);
        summaryStatistics.addValue(80.0);
        summaryStatistics.addValue(90.0);
        summaryStatistics.addValue(100.0);
        summaryStatistics.getStandardDeviation();
    


我以为JIT会消除死代码,所以会同时执行两个方法。但最后,我有:

summaryStatistics_standardDeviationForFourNumbers 0.158 ± 0.046 DeadCodeTraps.summaryStatistics_standardDeviationForTenNumbers 0.359 ± 0.294

为什么 JIT 不优化它? summaryStatistics.getStandardDeviation(); 的结果不会在方法之外的任何地方使用,也不会被它返回。

(我使用的是OpenJDK build 10.0.2+13-Ubuntu-1ubuntu0.18.04.4)

【问题讨论】:

什么代码死在这里?您是否希望这两个代码花费相同的时间? 期望具体是什么?我对这个结果一点也不感到惊讶 summaryStatistics.getStandardDeviation(); 不在方法范围之外的任何地方使用或返回,因此在 JIT 优化后保留该代码没有意义?或者它可能会保留它,因为它无法确定这段代码是否有任何副作用? 【参考方案1】:

如果您谈论的是 Apache Commons Math SummaryStatistics 课程,那么它就是一个庞大的课程。它的构造肯定不会被内联。要了解原因,请使用 -XX:+UnlockDiagnosticVMOptions -XX:+PrintInlining -XX:-BackgroundCompilation 运行

内联后会消除死代码。 未使用的对象将反向传播,但非内联构造函数将破坏链,因为 JIT 优化器不再确定没有副作用。

也就是说,你期望被淘汰的代码太大了。

【讨论】:

是的,你是对的。首先,我想使用来自java.utilDoubleSummaryStatistics,但我搞砸了导入。在DoubleSummaryStatistics 的情况下,它是内联的并且具有与空方法几乎相同的结果。谢谢!

以上是关于JMH - 为啥 JIT 不能消除我的死代码的主要内容,如果未能解决你的问题,请参考以下文章

JUC并发编程 -- JIT即时编译器之锁清除

为啥 GCC 不能消除多个继承函数的歧义(但 clang 可以)? [复制]

如何处理网站的死链接

在 JMH 中对具有不同值的循环进行微基准测试

JIT对锁的优化- 锁消除和锁粗化案例分析

用于对 Java 类进行基准测试的 JMH 与 JMeter?