gongdear

gongdear的技术博客

欢迎大家参观我的博客
  menu
99 文章
89355 浏览
3 当前访客
ღゝ◡╹)ノ❤️

知乎上一个关于Java性能问题的探究

今天在知乎上看到一个问题很有意思:

// 下面一小段程序, 修改注释处所指的常数, 并不影响函数调用次数和结果, 但运行时间差距很大.
// 常数=1时只需0.125秒; 常数=2时需要2.1秒; 常数=4时需要6.1秒.
// 测试环境是 OpenJDK 11.0.1 64-bit, Win10 64-bit
public class A {
	int v;
	public static void main(String[] args) {
		A a = new A();
		Runnable[] r = new Runnable[] {
			() -> a.v++,
			() -> a.v++,
			() -> a.v++,
			() -> a.v++,
		};
		for (int i = 0; i < 1000000000; i++)
			r[i % 1].run(); // 这里的1改为2和4的三种情况性能有极大差距
		System.exit(a.v);
	}
}

自己运行了一下,结果与问题描述的时间基本一致,常数为1时i%1的结果恒为0,猜测jvm应该做了优化。
使用javap查看bytecode.发现除第59行使用不同参数外,无任何不同。
参数1使用,iconst_1,参数2使用iconst_2,参数4使用iconst_4,使用hsdis查看jit生成的汇编.发现jit进行了很多优化。
使用参数1的汇编被优化为类似

for (int i = 0; i < 1000000000; i++)
  a.v++;

猜测被证实了,jvm确实很聪明。

使用参数2的汇编被优化为类似

for (int i = 0; i < 1000000000; i++)
  switch(i){
    case 0: A$Lambda$1();break;
    case 1: A$Lambda$2();
  }

这里A$Lambda函数也有优化。

使用参数4的应该是没有优化,所以性能最低。

宝剑锋从磨砺出,梅花香自苦寒来.