2012-03-20 49 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