最近工作遇到了一個問題,原本在32位Android機上跑的好好的程序,在某些64位機上卻變慢了許多。感覺很奇怪,所以google了一下原因,網上給出的原因大部分是過多使用指針。可是為什么過多使用指針就會造成程序變慢呢?結合網上的資料,和自己的理解,我認為是如下原因造成的:
(1)因為64位比32位的指針大了一倍,尋址空間從2^32大幅上升到2^64,但是這也帶來了額外的問題。一個指針的存儲空間也變成了原來的兩倍,在做指針運算時,例如int*ptr,*(ptr+5),移動距離也變為了原來的兩倍。
(2)如果cpu的緩存大小不變,假設為10k=1024*10byte。原來一個指針只占用4byte,緩存中能存儲2560個指針。現在由於指針占用空間變大,只能存儲1280個了。
(3)假設程序中需要讀取某個指針的數據,可以簡單分為兩種情況:如果該數據在緩存中,那么直接做指針取數據運算;如果該數據不在緩存中,程序就需要從內存中尋找數據並更新緩存(這部分機制不是特別熟悉,姑且這么理解吧……)。
(4)在上述情況下,如果程序中對內存的訪問經常“跳躍”的話(例如不是i++,而是i+=10),考慮到64位機的指針長度變成了32位機的兩倍,那么移動時會比之前慢一些。更嚴重的是,程序還會更頻繁的在緩存中尋找數據失敗,導致從內存尋找數據並更新緩存,這樣讀取數據操作的耗時就會提高,程序的運行速度也會顯著下降。
綜上所述,如果某個android機廠商為了偷工減料,把cpu升級成64位后,緩存容量卻不升級,而恰好你的程序中又有很多不連續的指針運算,那么程序的運行速度就會變慢很多(我們這邊的程序運行速度變慢了50%)。另一方面,如果某個android機廠商比較有良心的話,把cpu升級成64位后,緩存容量也跟着升級了,那么程序變慢的現象就基本不會出現。以上兩種情況,我在不同廠商的手機上都遇到過,就不點名了。對於Android開發者,尤其是做NDK開發的,還是需要多考慮內存使用方面的優化,如果有頻繁的內存申請/釋放,最好還是利用內存池等技術避免。
參考資料:
【1】http://www.quora.com/I-came-to-know-that-a-64-bit-architecture-machine-working-with-a-64-bit-OS-works-10-15-slower-than-a-32-bit-OS-working-on-the-same-machine-Why-is-that
【2】http://android-developers.blogspot.com/2015/07/game-performance-data-oriented.html
