跳转至

0.1f 改为 0 后性能下降 10 倍问题(StackOverflow)

一、现象

StackOverflow 上的著名问题:一段计算代码,把 0.1f 改成 0f,结果性能反而下降 10 倍。

二、根因:JIT 的优化假设

HotSpot JIT 在编译时会根据常见情况做激进优化。当代码里有 0.1f 这种非常量浮点数运算时,JVM 假设"这是正常业务计算",会:

  • 用 FPU / SSE 指令,按 float 精度运算。
  • 不做特殊优化。

改成 0f 后,JIT 可能进入另一种优化路径:

  • 它发现结果总是 0,但不能直接消除计算(因为 NaN、Infinity 等边界情况)。
  • 它做了一些"投机优化",假设不会出现特殊浮点值。
  • 一旦运行时真的出现 NaN / Infinity,要去优化(deoptimization),回到解释执行。

更常见的解释:0 让 JVM 误以为是整数运算,用了不同的指令路径,而 float 转 double / int 转换在某些 CPU 上反而慢

三、本质

这是 JIT 的"优化黑魔法":

  • 不能凭直觉猜性能。
  • 改一个常量就 10 倍差异,说明 JIT 生成的机器码完全不同。
  • 微基准测试要排除 JVM 预热、JIT、去优化等因素。

四、启示

  1. 不要靠感觉优化,用 JMH 测。
  2. 微基准测试要正确:预热、多线程、Blackhole 防止死代码消除。
  3. JVM 的优化非常复杂,"改个常量没影响"是错觉。

五、JMH 示例

@Benchmark
public float testFloat() {
    float sum = 0;
    for (int i = 0; i < 1000; i++) {
        sum += 0.1f * i;
    }
    return sum;
}

面试加分

  • 这道题考的不是具体代码,而是对 JIT 优化、去优化、微基准测试的理解。
  • 答出"JVM 会根据运行时 profile 做激进优化,改个常量可能让整个编译路径不同"。