最近工作遇到了一个问题,原本在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