參考文章鏈接:關(guān)于Xcode編譯性能優(yōu)化的研究工作總結(jié)
一、編譯時長優(yōu)化Architectures
在Build Setting 中,有個Architectures配置選項。
Architectures: 是指定工程支持的指令集的集合,如果設(shè)置多個architecture,則生成的二進(jìn)制包會包含多個指令集代碼,提及會隨之變大。
Valid Architectures: 有效的指令集集合,Architectures與Valid Architectures的交集來確定最終的數(shù)據(jù)包含的指令集代碼。
Build Active Architecture Only :指定是否只對當(dāng)前連接設(shè)備所支持的指令集編譯,默認(rèn)Debug的時候設(shè)置為YES,Release的時候設(shè)為NO。Debug設(shè)置為YES時只編譯當(dāng)前的architecture版本,生成的包只包含當(dāng)前連接設(shè)備的指令集代碼;設(shè)置為NO時,則生成的包包含所有的指令集代碼(上述的Valid Architecture與Architectures的交集)。所以為了更快的編譯速度,Debug應(yīng)設(shè)為YES,而Release應(yīng)設(shè)為NO。
PS:Debug設(shè)置為YES時,如果連接的設(shè)備是arm64的(iPhone 5s,iPhone 6(plus)等),則Valid Architecture中必須包含arm64,否則編譯會出錯。這種模式下編譯出來的版本是向下兼容的,即:編譯出的armv6版本可在armv7版本上運行。
二、編譯時長優(yōu)化Precompile Prefix Header 預(yù)編譯頭文件
Xcode6以及之后版本默認(rèn)不適用PCH文件參與項目編譯,原因有二:
- 去掉自動導(dǎo)入的系統(tǒng)框架類庫的頭文件可以提高源文件的復(fù)用性,便于遷移;
- 一個龐大的Prefix Header 會增加Build耗時
但對于原項目應(yīng)用了PCH文件的情況,就需要對Xcode的Build Setting進(jìn)行配置以使用pch。
當(dāng)Precompile Prefix Header設(shè)為NO時,頭文件pch不會被預(yù)編譯,而是在每個用到它導(dǎo)入的框架類庫中編譯一次。每個引用了pch內(nèi)容的.m文件都要編譯一次pch,這會降低項目的編譯速度。
將Precompile Prefix Header設(shè)為YES時,pch文件會被預(yù)編譯,預(yù)編譯后的pch會被緩存起來,從而提高編譯速度。 需要編譯的pch文件在Prefix Header中注冊即可。
三、加載RAM磁盤編譯Xcode項目
DerivedData
Xcode會在文件系統(tǒng)中幾種緩存臨時信息。
每次對Xcode iOS項目進(jìn)行clean、build或者在iOS虛擬機上launch,Xcode都會在DeriveData文件夾中進(jìn)行讀寫操作。換句話說,就是將Derived Data的讀寫從硬盤移動到內(nèi)存中。
DeriveData文件夾中包含了所有的build信息、debug- 和 release- built targets以及項目的索引。當(dāng)遇到零散索引(odd index)問題(代碼塊補全工作不正常、經(jīng)常性的重建索引、或者運行項目緩慢)時,它可以有效地刪除衍生數(shù)據(jù)。刪除這個文件夾將會導(dǎo)致所有Xcode上的項目信息遭到破壞。
步驟1
將DeriveData下的文件刪除:
hdid -nomount ram://4194304 ```
刪除這些數(shù)據(jù),Xcode會在Build時重新寫入
*步驟2*
在~/Library/Developer/Xcode/DerivedData.上部署安裝2 GB大小的RAM磁盤。 進(jìn)到
~/Library/Developer/Xcode/DerivedData.
` cd ~/Library/Developer/Xcode/DerivedData`
創(chuàng)建2 GB的RAM磁盤(size的計算公式 size = 需要分配的空間(M) * 1024 * 1024 / 512):` hdid -nomount ram://4194304 `
此行命令后將會輸出RAM磁盤的驅(qū)動名字:/dev/diskN(N為數(shù)字)。
初始化磁盤:`newfs_hfs -v DerivedData /dev/rdiskN`
有以下輸出: Initialized /dev/rdisk3 as a 2 GB case-insensitive HFS Plus volume
安裝磁盤:`diskutil mount -mountPoint ~/Library/Developer/Xcode/DerivedData /dev/diskN `
這會在已存在的DeriveData上安裝一個卷,用于隱藏舊的文件。這些文件仍會占據(jù)空間,但在移除RAM磁盤之前都無法訪問。
在重啟或從Finder中彈出RAM磁盤時,磁盤內(nèi)容會消失。下次再創(chuàng)建磁盤時,Xcode將會重新構(gòu)建它的索引和你的項目中的中間文件。
創(chuàng)建虛擬磁盤后,并不直接占用掉所有的分配空間,而是根據(jù)虛擬磁盤中的文件總大小來逐漸占用內(nèi)存。
注意:如果虛擬磁盤已滿,會導(dǎo)致編譯的失敗。此時清除掉DeriveData后zhong重新編譯,就算有足夠的空間也還是有可能會導(dǎo)致編譯失敗。重啟Xcode可以解決此問題。
### 四、編譯線程數(shù)和Debug Information Format
- **4.1、 提高XCode編譯時使用的線程數(shù)**
`defaults write com.apple.Xcode PBXNumberOfParallelBuildSubtasks 8 `
其后的數(shù)字為指定的編譯線程數(shù)。XCode默認(rèn)使用與CPU核數(shù)相同的線程來進(jìn)行編譯,但由于編譯過程中的IO操作往往比CPU運算要多,因此適當(dāng)?shù)奶嵘€程數(shù)可以在一定程度上加快編譯速度。
- **4.2、 將Debug Information Format改為DWARF**
在工程對應(yīng)Target的Build Settings中,找到Debug Information Format這一項,將Debug時的DWARF with dSYM file改為DWARF。
需要注意的是,將Debug Information Format改為DWARF之后,會導(dǎo)致在Debug窗口無法查看相關(guān)類類型的成員變量的值。當(dāng)需要查看這些值時,可以將Debug Information Format改回DWARF with dSYM file,clean(必須)之后重新編譯即可。
ps:4.2的解決方案為Xcode的默認(rèn)設(shè)置,進(jìn)行反向設(shè)置時,編譯速度改變不大;
### 五、Link-Time Optimizations 鏈接時優(yōu)化
Link-Time Optimization執(zhí)行鏈接時優(yōu)化(LTO)。在Clang/LLVM領(lǐng)域,這意味著鏈接器獲得的是LLVM字節(jié)碼,而不是通常的目標(biāo)文件。這些字節(jié)碼在一種更抽象的層次上代表程序這里寫鏈接內(nèi)容的執(zhí)行過程,允許LTO得以進(jìn)行,但是壞處是,仍然需要將他們轉(zhuǎn)換成機器代碼,在鏈接時需要額外的處理時間。
參數(shù)設(shè)為YES時,能夠優(yōu)化鏈接時間;目標(biāo)文件以LLVM二進(jìn)制文件格式存儲,在鏈接期間,優(yōu)化了整個程序。
將其設(shè)為NO時,可以減少Link階段的時間。對于Link階段耗時較長的項目,整體編譯優(yōu)化體現(xiàn)較為明顯。
### 六、加裝SSD固態(tài)硬盤
固態(tài)硬盤傳輸速度能達(dá)到500MB/s,其中讀取速度達(dá)到400-600MB每秒,寫入速度達(dá)到200MB每秒。而傳統(tǒng)硬盤讀取速度極限也無法超越200MB每秒,寫入速度在100MB每秒左右。如果遇到非連續(xù)的散片數(shù)據(jù),SSD能體現(xiàn)出極快的讀寫速度。而傳統(tǒng)機械硬盤由于磁頭尋道等原因,傳輸速度偏慢。
SSD加快了程序的I/O速率,讀寫速度比普通硬盤快,從而提升Xcode的編譯速度。
###七、安裝包大小優(yōu)化 Asset Catalog Compiler - Options Optimization
Build Setting->Asset Catelog Compiler -> Options
在Optimization優(yōu)化設(shè)置項有三個選項,不制定、time和Space
Optimization nothing是Xcode默認(rèn)的設(shè)置。 與預(yù)想的不同,在選擇Optimization time 時,編譯時長并沒有得到優(yōu)化。 但在Optimization space時,編譯耗時基本沒有波動,但編譯生成的app 大小有不小程度的優(yōu)化。
### 八、安裝包大小優(yōu)化 Flatten Compiles XIB Files
是否流暢編譯XIB文件
>指定是否在編譯時剝離storyBoard文件以優(yōu)化它們的大小,設(shè)為YES時編譯出來的文件會被壓縮,但是不能編輯。
### 九、安裝包大小優(yōu)化,清理未被使用的圖片資源
**LSUnusedResources**
項目的開發(fā)過程總是會經(jīng)歷較長期的迭代,不斷的添加功能的同時會引入大量的圖片資源。需求變更、業(yè)務(wù)邏輯修改等需要移除某些功能模塊時就會導(dǎo)致這些前期加入的圖片資源問價被忽略而遺留在編譯的安裝包中,長此以往會使得安裝包變得格外臃腫。特別是類似于手Q項目的開發(fā),開發(fā)人員多,產(chǎn)品迭代頻繁,開發(fā)時間緊俏,開發(fā)人員輪換等特點更有可能導(dǎo)致這樣的后果。
一個較為傳統(tǒng)的清理方法時將圖片資源的文件名一一復(fù)制粘貼到Xcode的全局變量查找中去查找該字符串,如果返回的結(jié)果為零,則該資源很有可能沒被使用。之所以是“很有可能”,是因為在代碼中,資源有時是通過字符串拼接的方式進(jìn)行引用的。
在這里提供一個github上的開源工具 LSUnusedResources ,這個工具是對github上的另一個開源工具Unused的優(yōu)化改進(jìn)(匹配速度、結(jié)果準(zhǔn)確性),作者針對源碼、Xib、Storyboard 和 plist 等文件,先全文搜索其中可能是引用了資源的字符串,然后用資源名和字符串做匹配,從而找出未被使用的資源,比Unused的查找速度要快得多。
使用起來也比較簡單:
1、將工程目錄路徑拷貝到Folder或通過Browse瀏覽文件目錄;
2、在Resource指定要查找的資源類型; (經(jīng)過本人測試,發(fā)現(xiàn)該工具在未指定Resource類型時所查找出來的資源不是很準(zhǔn)確,列舉出 的資源事實上是正在使用的,所以我在測試時指定查找了png類型的文件。)
3、單擊Search以查閱結(jié)果。
注:為了避免對資源的誤刪操作,建議在該工具輸出結(jié)果后對結(jié)果中的資源名復(fù)制并在Xcode的全局查找
中進(jìn)行校驗。
下載安裝:[LSUnusedResources.app.zip](https://github.com/tinymind/LSUnusedResources/raw/master/Release/LSUnusedResources.app.zip)
Github地址:[LSUnusedResources](https://github.com/tinymind/LSUnusedResources)
參考鏈接:[查找XCode工程中沒被使用的圖片資源](http://blog.csdn.net/qq_25131687/article/details/blog.lessfun.com/blog/2015/09/02/find-unused-resources-in-xcode-project/)
### 十、安裝包大小優(yōu)化Deployment Postprocessing和Strip Linked Product
Xcode中Strip Linked Product 的默認(rèn)設(shè)置為YES,但是Deployment Postprocessing的默認(rèn)設(shè)置為NO。在Deployment Postprocessing 是Deployment的總開關(guān),所以在打開這個選項之前 Strip Linked Product是不起作用的。
ps:當(dāng)Strip Linked Product設(shè)為YES的時候,運行app,斷點不會中斷,在程序中打印`[NSThread callStackSymbols]`也無法看到類名和方法名。而在程序崩潰時,函數(shù)調(diào)用棧中也無法看到類名和方法名。
打開這兩個選項之后進(jìn)行編譯,編譯出的安裝包有了較大程度的優(yōu)化。
### 十一、安裝包大小優(yōu)化 Linking->Dead Code Stripping
將Dead Code Stripping 設(shè)置為YES 也能夠一定程度上對程序安裝包進(jìn)行優(yōu)化,只是優(yōu)化的效果一般,對于一些比較小的項目甚至沒有什么優(yōu)化體現(xiàn),所以這里也就沒有上測試數(shù)據(jù)。
Dead Code Stripping 是對程序編譯出的可執(zhí)行二進(jìn)制文件中沒有被實際使用的代碼進(jìn)行Strip操作