iOS 7: 如何為iPhone 5S編譯64位應(yīng)用
隨著iPhone5S的推出,大家開始關(guān)心5S上所使用的64位CPU A7。
除了關(guān)心A7的性能以外,大家還會(huì)關(guān)心一個(gè)問題,那就是使用A7的64位系統(tǒng)對應(yīng)用有沒有什么要求。特別是應(yīng)用開發(fā)者,大家都比較關(guān)心我們的應(yīng)用如何遷移到 64位的系統(tǒng)上來,以充分發(fā)揮A7的能力。其實(shí)這些問題都可以在蘋果的官方文檔《64-Bit transition Guide for Cocoa Touch》中找到答案。
為了方便大家,我將《64-Bit transition Guide for Cocoa Touch》中的一些重點(diǎn)整理了一下,希望可以為大家節(jié)約一些詳細(xì)閱讀文檔的時(shí)間,如果我理解有不對的地方請大家指正。
首先,A7使用的是ARM V8架構(gòu),除了使用64位的地址總線和64位的寄存器以外,還增加了寄存器的數(shù)量,目前A7中的整數(shù)和浮點(diǎn)數(shù)寄存器是A6的兩倍。
這里需要強(qiáng)調(diào)的是,寄存器的增加大大提高了程序的運(yùn)行速度。將CPU由32位提高到64位,最主要的改變增大了尋址能力,可以突破32位系統(tǒng)只能訪問3G內(nèi)存的限制(32位系統(tǒng)在理論上可以訪問4G內(nèi)存,因?yàn)?的32次方約等于4 290 000 000,很多32位系統(tǒng)只能訪問3G左右的內(nèi)存是因?yàn)橛幸淮蟛糠值刂繁环峙浣oI/O系統(tǒng)了,所以總體可用內(nèi)存就不足4G了),但是,32位到64位的改變并不一定意味著程序運(yùn)行速度的提高,甚至有些情況下會(huì)因?yàn)?4位系統(tǒng)中的數(shù)據(jù)占用內(nèi)存變大而導(dǎo)致程序運(yùn)行速度變慢。而寄存器數(shù)量的增加,則直接提高了程 序運(yùn)行速度,當(dāng)然,前提是你的應(yīng)用需要重新為64位系統(tǒng)編譯一遍,讓程序可以充分使用所有的寄存器。
使用Xcode 5可以很方便地將以前的應(yīng)用編譯成64位程序,基本過程如下:
- 1. 使用Xcode 5 打開原有項(xiàng)目。
- 2. 將支持的設(shè)備改成“iOS 7”。
- 3. 在“Build Setting”中將“Architectures”改成“Standard Architectures (including 64-bit)”。
- 4. 運(yùn)行測試程序,解決編譯過程出現(xiàn)的問題。
其中第4步是關(guān)鍵,具體會(huì)遇到什么問題和原來程序的設(shè)計(jì)有關(guān),包括使用數(shù)據(jù)類型的方式是否標(biāo)準(zhǔn)等,后面會(huì)繼續(xù)討論細(xì)節(jié),其實(shí)《64-Bit transition Guide for Cocoa Touch》一書主要就是講這些細(xì)節(jié)。
在討論細(xì)節(jié)之前有一些較為宏觀的內(nèi)容大家可以了解一下。
Xcode 5編譯的iOS 7程序包含了32位和64位兩套二進(jìn)制代碼,在32位的iOS系統(tǒng)上會(huì)調(diào)用32位的二進(jìn)制代碼,在64位系統(tǒng)上會(huì)調(diào)用64位的二進(jìn)制代碼,以此來解決向后兼容的問題。
同時(shí),考慮到很多32位的程序可能在沒有重新編譯的情況下部署到64位系統(tǒng)上,64位的iOS系統(tǒng)中帶有兩套FrameWork,一套是32位的,一套是64位的。
當(dāng)64位的iOS系統(tǒng)運(yùn)行原來的32位程序時(shí),系統(tǒng)會(huì)調(diào)用32位的FrameWork作為底層支撐,當(dāng)系統(tǒng)運(yùn)行64位程序時(shí),系統(tǒng)會(huì)調(diào)用64位的FrameWork作為底層支撐。
也就是說,當(dāng)一個(gè)iPhone 5S上同時(shí)運(yùn)行32位程序和64位程序時(shí),系統(tǒng)同時(shí)將32位和64位兩套FrameWork載入了內(nèi)存中,所以消耗的內(nèi)存也比較多。
如果一臺(tái)64位的iOS設(shè)備上運(yùn)行的所有程序都是為64位系統(tǒng)編譯過的,iOS系統(tǒng)將只載入64位的FrameWork,這將節(jié)省好多內(nèi)存。所以,如果大家都可以快速將程序傳換成64位的,iOS將跑得更快。真的是“大家好才是真的好”。
后面我們來看看一些為64位系統(tǒng)調(diào)整程序的技術(shù)細(xì)節(jié)。
32位的iOS系統(tǒng)和64位的iOS系統(tǒng)主要的差別有兩個(gè),一個(gè)是數(shù)據(jù)類型的差別,一個(gè)是過程調(diào)用方法的差別。
在數(shù)據(jù)類型上,主要的變化是指針類型(Pointer)和長整數(shù)類型(long)的長度變化和內(nèi)存對齊方式的變化,同時(shí)也導(dǎo)致了更高級(jí)別數(shù)據(jù)類型的變化,如NSInteger的長度也有變化。
在過程調(diào)用方法上,因?yàn)锳RM V8 和ARM V7具有不同數(shù)量的寄存器,具有不同的過程調(diào)用約定,所以32位系統(tǒng)和64位系統(tǒng)在匯編層級(jí)是不同的。
根據(jù)以上兩方面的變化,書中總結(jié)了以下要點(diǎn),開發(fā)人員根據(jù)以下要點(diǎn)來檢查原來的32位代碼就差不多可以將應(yīng)用移植到64位系統(tǒng)上了:
1. 不要將長整型數(shù)據(jù)(long)賦予整型(int)
這種代碼在32位系統(tǒng)上沒有問題,因?yàn)樵?2位系統(tǒng)中l(wèi)ong和int的長度是一樣的,不過在64位系統(tǒng)中就有可能出問題,因?yàn)?4位系統(tǒng)中l(wèi)ong比int長,將long值賦予int將導(dǎo)致數(shù)據(jù)丟失。
2. 不要將指針類型(Pointer)賦予整型(int)
為 了方便地址計(jì)算,有時(shí)程序員會(huì)將指針類型賦予整型,這種代碼在32位系統(tǒng)上沒有問題,因?yàn)樵?2位系統(tǒng)中Pointer和int的長度是一樣的,不過在 64位系統(tǒng)中就會(huì)有問題,因?yàn)?4位系統(tǒng)中Pointer比int長,將Pointer值賦予int將導(dǎo)致地址數(shù)據(jù)丟失,最終導(dǎo)致嚴(yán)重問題。
3. 留意那些和數(shù)位相關(guān)的數(shù)值計(jì)算
比如掩碼技術(shù),如果使用一個(gè)long類型的掩碼,轉(zhuǎn)到64位系統(tǒng)后高位都是0,計(jì)算出來的結(jié)果可能不符合預(yù)期。還有無符號(hào)整數(shù)和有符號(hào)整數(shù)的混用等。
4. 留意對齊方式帶來的變化
如果在32位系統(tǒng)上定義一個(gè)結(jié)構(gòu)包含兩個(gè)long類型,第二個(gè)long數(shù)值的偏移地址是4,可以通過結(jié)構(gòu)地址+4的方式獲取,但是在64位系統(tǒng)上就不行了,因?yàn)樵?4位系統(tǒng)中第二個(gè)long數(shù)值的偏移地址是8。
5. 充分考慮在32位應(yīng)用和64位應(yīng)用之間的數(shù)據(jù)交換
因 為用戶會(huì)通過網(wǎng)絡(luò)交換數(shù)據(jù),同時(shí)用戶保存的數(shù)據(jù)也可能通過備份等方式在32位系統(tǒng)和64位系統(tǒng)之間切換,所以應(yīng)用在保存和發(fā)送流數(shù)據(jù)的時(shí)候一定要考慮充 分。比如數(shù)據(jù)在32位系統(tǒng)中保存,在64位系統(tǒng)中能否正常打開,或者反過來,在64位系統(tǒng)中保存,在32位系統(tǒng)中打開是否正常。
6. 重寫所有匯編代碼
這點(diǎn)無需說明,如果你在代碼中嵌入了匯編代碼,你需要參考64位系統(tǒng)的指令集重寫匯編代碼。
7. 不要將可變參數(shù)的過程強(qiáng)制轉(zhuǎn)換為定參過程,也不要將定參過程強(qiáng)制轉(zhuǎn)換為可變參數(shù)的過程
這時(shí)因?yàn)?2位系統(tǒng)和64位系統(tǒng)對于這兩種過程調(diào)用方式的處理方法不同。
按以上幾個(gè)重點(diǎn)去檢查程序就差不多了,當(dāng)然,具體的細(xì)節(jié)還有很多,需要在實(shí)際工作中結(jié)合代碼和調(diào)試結(jié)果進(jìn)行分析。
總之,建議具體負(fù)責(zé)應(yīng)用遷移的開發(fā)者需要完整閱讀《64-Bit transition Guide for Cocoa Touch》。