iOS之性能优化·提高App的编译速度
生活随笔
收集整理的這篇文章主要介紹了
iOS之性能优化·提高App的编译速度
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
一、前言
- 經過多年的開發和迭代,我相信很多的 iOS 項目代碼已經達到幾十萬行甚至上百萬行的規模,所使用的 Pod 庫的數量可以達到幾十個甚至上百個,App Store 安裝包也變得越來越大,在這么大的項目規模下,打包和編譯問題逐步成為開發團隊一個躲不過的痛,嚴重影響了研發效率與其他團隊之間的協作。
- 有時間,一臺機器同時需要承接七八個項目,多個分支的打包任務,在有多個項目同時打包的情況,尤其顯得力不從心。
- 在硬件資源有限的情況下,并且在無侵入、無影響現有的業務的前提下,如何解決這些成為擺在團隊面前的難題和迫在眉睫的需求,怎么加快打包速度成為了一個需要優化處理的重要事項。
二、編譯提速探索與嘗試
① CCache
- CCache 是一個編譯緩存器,一個能夠把編譯的中間產物緩存起來的工具。
- CCache 的原理是通過把項目的源文件用 ccache 編譯器編譯,然后緩存編譯生成的信息,從而在下一次編譯時,利用這個緩存加快編譯的速度,目前支持的語言有:C、C++、Objective-C、Objective-C++;
- 如下所示,基本就闡述了 CCache 的工作原理:
- 在項目中的實際編譯流程:
- 經過在工程的一番嘗試,CCache 確實在某些方面上極大的提升了出包的速度。很多時候項目的打包速度的確減少了一半多,能夠給帶來比較不錯的提升,大大加快項目的出包速度。
- CCache 的優點如下:
-
- 能滿足追求的無侵入、無影響現有的業務的要求,無入侵、且開發人員無感知。
-
- 確實能大幅度地提升編譯速度,項目上最快時提高3倍以上的編譯速度。
-
- 不需要對項目作出大調整,只需部署相關環境和一些腳本支持。
-
- 不需要改變開發工具鏈。
-
- 同一個目錄下,CCache 的緩存命中率相對穩定。
- 很多時候開發的過程中,項目可能會存在以下問題:
-
- 在未有緩存的情況下,首次打包編譯的時間比原來的翻近一倍;
-
- 修改一些引用較多的文件(如公共庫、底層庫改動),容易造成大范圍的緩存失效,速度會變得比原來未使用 CCache 時更慢;
-
- 多個項目相同的組件不支持緩存共享,有多個分支打包的需求,修改目錄名稱后,緩存即失效;
-
- 機器的 CCache 最大的緩存上限約 18GB,且 Debug/Release 區別緩存,項目會占用幾個GB+的緩存,多個項目、多個分支很容易超出上限,一臺機器同時支持多個項目會觸發 CCache 清緩存;
-
- 對機器硬盤讀寫要求高,如不是全部固態硬盤,速度影響大;
-
- CCache 不支持 Clang Modules,系統框架例如 AVFoundation、CoreLocation 等, Xcode 不會再幫你自動引入,會導致編譯失敗;
-
- CCache 不支持 PCH 文件;
-
- CCache 目前不支持 Swift。
② 靜態庫二進制方案的探索
- 使用二進制編譯的自研任務,可以更進一步提高研發效率。
- 項目使用 CocoaPods 來管理第三方庫和私有庫的依賴,對大部分項目來說應該是標配。目前還是純 Objective-C 的項目,有少量 C++,暫沒有引入 Swift。
③ 調研過的二進制組件方案
- Carthage 可以將一部分不常變的庫打包成 framework,再引如到主工程,這樣可以減少開發過程中的編譯時間。Carthage 可以比較方便地調試源碼,如果項目大規模使用 CocoaPods,轉用 Carthage 來做包管理需要做大量的轉換工作,變動太大,不滿足的無侵入、無影響現有的業務,這個方案不太適合。
- cocoapods-packager 可以將任意的 pod 打包成 Static Library,省去重復編譯的時間,一定程度上可以加快編譯時間,但是也有自身的問題:
-
- 優化不徹底,只能優化第三方和私有 Pod 的編譯速度,對于其他改動頻繁的業務代碼無能為力;
-
- 私有庫和第三方庫的后續更新很麻煩,當有源碼修改后,需要重新打包上傳到內部的 Git 倉庫;
-
- 過多的二進制文件會拖慢 Git 的操作速度(目前還沒部署 Git 的 LFS);
-
- 難以調試源碼,不共享編譯緩存;
-
- 打包成 Static Library 過程緩慢,需要通過pod lint,各個組件間又層層嵌套依賴,在現有階段來說,是難以實現的。
- Cocoapods-Binary(Cocoapods 官方推薦的二進制插件), 是一個即時生成二進制包并緩存,而非像 CocoaPods-Packager 僅僅針對單個私有庫的。原理是通過 CocoaPods 提供的 pre_install hook 在 pod install 的 prepare 階段攔截到當前的 pod install context,進而 fork 出一份獨立的 installer 以完成將預編譯源碼 clone 至 Pod/_Prebuild 目錄下,同時也存在幾個不足之處:
-
- 單私有源,無法實現服務端緩存,在沒有對應二進制包版本時,pod install 后會額外去做二進制包的生成,一定程度上會影響 pod install的速度;
-
- 開發者切回源碼調試,二進制緩存會一并清空,需求重新編譯;
-
- 多個項目、不同分支的相同組件依舊無法共享;
-
- 只支持 framework,對項目需要比較大的頭文件引用方式改動。
- cocoapods-bin 雙私有源:該插件進行二進制化的策略是采用雙私有源,即2個源地址,一個靜態服務器保存預先打好包的 framework,一個是保存源碼的服務地址。它的優點:
-
- 源碼和二進制文件之間可以來回切換,速度比較快;
-
- 不影響未接入二進制化方案的業務團隊;
-
- 無二進制版本時,自動采用源碼版本;
-
- 接近原生 CocoaPods 的使用體驗。
三、雙私有源二進制組件簡介
- 受到 cocoapod-bin 啟發后,在借鑒它的部分框架下,可以實現二進制輔助插件cocoapods-imy-bin,新增命令和二進制源碼調試能力。
① 只要能編譯通過,就制作
- 在 cocoapods-imy-bin 的輔助下,能無侵入式自動化地制作所有符合條件的組件為二進制,且對于頻繁的業務組件也能輕松的應用上二進制組件,無需多余操作,一切交給 cocoapods-imy-bin 自動化運行。
- 同時對于研發人員,也能提供獨立的二進制組件給研發人員使用,解決日常的編譯 效率、跑真機效率低下,被墻等各種問題。
- 只要能編譯通過,就制作,一次編譯到處使用,無入侵。即使獨立的組件庫編譯不通過,整體項目能編譯通過也制作。整套環境下來,可以不讓開發人員改變原來的開發習慣,不需要改動業務中相關的代碼,基本上做到了使用人員無感知狀態。
② Ci 打包效果
- 如下所示:這是打包幾千個的經驗得出對單個項目編譯時間大致的曲線圖,這里假設一臺機器只一次只有一次job,Y軸編譯時間,X軸某次的編譯, 紅色線條表示的是原生(未使用 CCache 和二進制組件),黃色線表示使用了CCache,藍色表示使用了二進制組件:
- 由圖可以看出來在無任何輔助下原生的編譯時間曲線(紅色)是趨于平緩,在20min上下左右。CCache 和二進制第一次在無任何緩存的情況下,在一定程度上是會比原生的耗時,CCache 主要耗時在邊編譯邊緩存項目的編譯產物。二進制主要耗時在編譯完成后,對 .a 編譯產物的組裝和 push 到私有源倉庫的時間上(這個跟所采用有關系,如果沒有利用Jenkins 編譯后的產物制作二進制就不存在)。
- 在 CCache 完全命中二進制文件完全都存在的情況下,CCache 比原生的提高一倍以上, 二進制會比 CCache 編譯時間再提高一倍,且穩定在2分鐘左右。二進制在之后的表現更趨于平穩,而 CCache 在修改了某個被引用較多的文件時、如底層的公共文件后,命中率就會大大地降低,有時會比不用 CCache 更耗時,如#4位置。在 ci 有多個 job 同時并發在跑的情況下,由于 CCache 需要對 IO 頻繁地讀寫操作,耗時表現可能會更糟糕些。
- 二進制的編譯時間相對平穩很多(藍色曲線),在架構強有力的支撐下,劃分出110多個獨立組件,每次的打包基本上是就耗在某個組件的編譯 +archive。如果是某些變更比較頻繁的組件,我們還可以考慮對顆粒較大組件配上 CCache,做雙層編譯緩存。雙層編譯緩存原理是 Pods 組件庫無二進制組件采用源碼編譯時,源碼編譯同時應用 CCache 緩存支持,加速源碼組件的編譯。
- 同時組件庫可以配合 Gitlab-Ci 的 runner 的應用,每次已提交代碼就觸發獨立組件的制作二進制,讓每次的編譯速度都達到最快,藍色二進制曲線將會更接近直線。
- 如果存在有獨立組件無法編譯問題和版本依賴問題,也可以再跑個定時 Job,或者其他輪詢條件 Job,及時提供最新二進制組件。
- 一臺機器上多個項目的 CCache 顯得是比較吃力的,且不穩定,超出 CCache 的緩存最大值就會被清掉。使用了二進制后,即使是多個項目編譯時間都是趨于比較平穩的。
③ 開發使用效果
- 在 Podfile 引入插件后,在 pod install/update 后,符合條件的情況下,會自動轉換為二進制組件。
- 源碼編譯:項目如果上百個 Pods 庫,有 20+ 個穩定 Pods 庫已經被制作為二進制庫,并非全部源碼編譯,如何全部轉換為源碼編譯,實際數字會比這多出很多。
- 在環境搭建完后,開發人員在 Podfile 中,加入以下兩句,就能享用到自動切換為二進制組件,體驗極速編譯。
四、功能點
- 目前 cocoapods-imy-bin 插件支持的功能如下:
-
- 無侵入、無影響現有的業務;
-
- 不影響未接入二進制化方案的業務團隊,提供配置文件;
-
- 只要項目能編譯通過就制作,即使獨立組件編譯失敗;
-
- 支持無二進制版本時,自動采用源碼版本;
-
- 支持只需項目能編譯通過就能制作二進制組件,無需再關心 pod lint 等;
-
- 支持 pod bin local 命令一鍵自動化制作、上傳、存儲項目本地已經存在的二進制組件,可配合 ci 打包的編譯產物使用;
-
- 支持指定依賴分支支持:podspec =>’’, :git 方式的引用;
-
- 支持同時 .a、Framework 靜態庫產出;
-
- 支持 archive 時,根據 Podfile 自動獲取 podsepc 依賴的庫,無需強制去 spec 倉庫拉取;
-
- 支持多套隔離環境,如 Debug/Release/Dev 配置,方便為 Debug/Release/Dev 各種環境提供專用二進制組件;
-
- 支持輸出 .a 二進制組件制作 binary.podsepc 無需模板;
-
- 支持穩定的二進制組件,在上傳二進制組件的 binary.podsepc 跳過 pod lint 驗證,加快速度;
-
- 支持 pod bin auto 命令一鍵自動化制作、上傳、存儲單個二進制組件;
-
- 支持 pod bin auto --all-make 命令一鍵自動化制作、上傳、存儲該項目下所有組件的二進制組件;
-
- 支持是否使用二進制文件、是否制作二進制文件和二進制/源碼調試功能的白名單設置;
-
- 支持 pod install/update 多線程模式,加快 pod 過程,Pod 速度提升 80%+;
-
- 支持 pod bin install/update 命令,實現無入侵修改 Podfile 內容,避免直接修改工程的 Podfile 文件而導致提交沖突、誤提交;
-
- 支持 pod bin code 命令,實現二進制庫不切換源碼庫,程序無需重新運行的調試能力。
總結
以上是生活随笔為你收集整理的iOS之性能优化·提高App的编译速度的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: iOS之性能优化·优化App的电池耗电量
- 下一篇: HarmonyOS之深入解析设备标识符的