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、去优化等因素。
四、启示¶
- 不要靠感觉优化,用 JMH 测。
- 微基准测试要正确:预热、多线程、Blackhole 防止死代码消除。
- 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 做激进优化,改个常量可能让整个编译路径不同"。