2012-03-20 50 views
2

我一直在做Android循环的一些实验,并对结果感到困惑。Android循环字节码比较

在过去,我读的地方,(在C++?)如果你翻译这个循环:

for(int i = 0; i != Integer.MAX_VALUE; i++) 
{ 
    // Do something 
} 

......这个循环:

for(int i = threshold; --i >= 0;) 
{ 
    // Do the same 
} 

你可以得到一个显著上升的性能,因为第二个变体会生成与零的比较,这归因于处理器体系结构比第一个循环中两个非零值之间的比较快得多。

我想看看这是否在Android中保持真实,所以我开始写代码并使用DEX偷看生成的Dalvik的字节码,以检查是否没有任何类型的编译器优化。

事实上,这些都是结果:

0003dc: 1201         |000e: const/4 v1, #int 0 // #0 
0003de: 1402 ffff ff7f       |000f: const v2, #float NaN // #7fffffff 
0003e4: 3321 5000        |0012: if-ne v1, v2, 0062 // +0050 

000434: 1401 ffff ff7f       |003a: const v1, #float NaN // #7fffffff 
00043a: d801 01ff        |003d: add-int/lit8 v1, v1, #int -1 // #ff 
00043e: 3b01 2800        |003f: if-gez v1, 0067 // +0028 

(这是不相关的代码,在0062和0067的问题,因为我只是通过循环它的自我关注)。

好吧,但我们可以清楚地看到编译器/转换器没有引入优化,因为两个循环语法都有不同的生成字节码。

现在的上下文设置,并且我证明,它会继续它的时候,这个问题测试有用:

“说完我异形上面的代码,并发现了不管的顺序第一个循环的执行总是需要比第二个更多的时间,我在这里错过了什么?“

就像JIT编译为我做一些优化?

我期望这两个循环的行为不同,因为生成的字节码是不一样的。

非常感谢在这个问题上给我的启发。

回答

1

在第一个程序集中,if-ne指令比较两个值(v1和v2)并根据结果跳转。这比只比较一个值和第二种情况下的if-gez指令时要慢。但是,也许我误解了你的问题,你的意思是这两个循环运行在相同的执行时间?它不是从你的问题不清楚。你有什么时机?

+0

感谢,威乐!正如我在Yury的评论中所说的那样,时间与循环的执行顺序无关。现在,无论你把它第一次将始终运行慢... – 2012-03-20 16:03:35

2

我有以下想法。首先,dalvik字节码不是直接在处理器上执行 - 它仍然是字节码,应该转换为本地代码。

其次,让我们考虑为什么在C++(x86平台)第二种情况下会更快,则第一:

  1. 所以在第一种情况下,你将有一个这样的代码:inc (i),然后 比较两个值处理器将从 秒中减去第一个值,并检查结果是否等于0(使用jz指令或类似的东西)。
  2. 在第二种情况下处理器将dec (i),然后将结果值将与0(使用JZ)进行比较。

因此,可以看到的是,第二壳体是一个指令更短。我猜在ARM处理器中会出现同样的情况,这就是为什么第二个循环比第一个更快。

+0

非常感谢,尤里!问题是:第二个循环不比第一个循环更快。如果切换去执行顺序(即运行第二个循环之前我首先提出)以后总是会更快。尽管您在运行之前将DEX转换为本地代码的想法可能会解释这个问题。 – 2012-03-20 15:59:37