隨著我們移動互聯(lián)網(wǎng)的興起到火爆,成千上萬款app營運而生,電商概荷、出行谭贪、音視頻专控、教育等等,五花八門漂彤,那么每一款A(yù)PP都會有對應(yīng)的人群去下載使用,那么用戶對一款app的鐘愛程度除了這款app很受喜愛和直接用途之外瞬逊,受大家喜愛并且留存在手機上長久不卸載的一個重要原因显歧,便是我們的app的性能,包括:啟動速度确镊、啟動后的流暢度士骤、app的安裝包體積、app運行對手機的電量消耗蕾域、app是否有閃退等拷肌,這幾個條件,決定了一款app是否優(yōu)秀旨巷。
下面我針對這幾個方面做下項目性能優(yōu)化的經(jīng)驗和知識點分享
目錄
- 項目啟動
- 項目運行
- 安裝包體積
- app的電量消耗
1.項目啟動
項目啟動環(huán)節(jié)巨缘,我們大致分為2種啟動:即冷啟動(Cold Launch
)和熱啟動(Warm Launch),針對優(yōu)化采呐,我們主要針對冷啟動
知識點:打印啟動時間
通過添加環(huán)境變量可以打印出APP的啟動時間分析(Edit scheme -> Run -> Arguments)
DYLD_PRINT_STATISTICS設(shè)置為1
如果需要更詳細的信息若锁,那就將DYLD_PRINT_STATISTICS_DETAILS設(shè)置為1
冷啟動大概又分為三個階段
1.dyld
2.Runtime
3.main函數(shù)
dyld
dyld(dynamic link editor),Apple的動態(tài)鏈接器斧吐,可以用來裝載Mach-O文件(可執(zhí)行文件又固、動態(tài)庫等)
啟動APP時,dyld所做的事情有:
裝載APP的可執(zhí)行文件煤率,同時會遞歸加載所有依賴的動態(tài)庫
當dyld把可執(zhí)行文件仰冠、動態(tài)庫都裝載完畢后,會通知Runtime進行下一步的處理
具體關(guān)于dyld的講解蝶糯,我推薦一篇文章dyld專題講解洋只,寫的不錯,后續(xù)我也會對dyld寫篇自己的理解的博客
Runtime
這里說的Runtime并不是要對Runtime進行底層講解昼捍,是針對程序的啟動流程的Runtime階段進行分析识虚,推薦一篇關(guān)于Runtime的底層講解iOS底層原理總結(jié) - 探尋Runtime本質(zhì)(一)
啟動APP時,runtime所做的事情有
- 調(diào)用map_images進行可執(zhí)行文件內(nèi)容的解析和處理
- 在load_images中調(diào)用call_load_methods端三,調(diào)用所有Class和Category的+load方法
- 進行各種objc結(jié)構(gòu)的初始化(注冊O(shè)bjc類 舷礼、初始化類對象等等)
- 調(diào)用C++靜態(tài)初始化器和attribute((constructor))修飾的函數(shù)
到此為止,可執(zhí)行文件和動態(tài)庫中所有的符號(Class郊闯,Protocol妻献,Selector蛛株,IMP,…)都已經(jīng)按格式成功加載到內(nèi)存中育拨,被runtime 所管理
Main函數(shù)
main函數(shù)的調(diào)用谨履,便是我們熟知的項目中Main入口和AppDelegate類里面的那一系列的調(diào)用了
總結(jié)一下優(yōu)化方案,按照階段:
dyld
減少動態(tài)庫熬丧、合并一些動態(tài)庫(定期清理不必要的動態(tài)庫)
減少Objc類笋粟、分類的數(shù)量、減少Selector數(shù)量(定期清理不必要的類析蝴、分類)
減少C++虛函數(shù)數(shù)量
Swift盡量使用struct
Runtime
用+initialize方法和dispatch_once取代所有的attribute((constructor))害捕、C++靜態(tài)構(gòu)造器、ObjC的+load
Main函數(shù)
- 在不影響用戶體驗的前提下闷畸,盡可能將一些操作延遲尝盼,不要全部都放在 finishLaunching方法中,例如三方注冊、啟動圖等
- 按需加載
2.項目運行
其實項目運行優(yōu)化佑菩,就涉及到我們的代碼優(yōu)化了盾沫,最常見也是影響最大的,就是
卡頓現(xiàn)象
針對卡頓現(xiàn)象的原因和優(yōu)化我在這里大概列舉一下殿漠,我會在另一篇關(guān)于CPU和GPU赴精,以及離屏渲染等方向進行講解
CPU優(yōu)化策略:
1.盡量用輕量級的對象,比如用不到事件處理的地方绞幌,可以考慮使用CALayer取代UIView
2.不要頻繁地調(diào)用UIView的相關(guān)屬性蕾哟,比如frame、bounds莲蜘、transform等屬性渐苏,盡量減少不必要的修改
3.盡量提前計算好布局,在有需要時一次性調(diào)整對應(yīng)的屬性菇夸,不要多次修改屬性
4.Autolayout會比直接設(shè)置frame消耗更多的CPU資源
5.圖片的size最好剛好跟UIImageView的size保持一致
6.控制一下線程的最大并發(fā)數(shù)量
7.盡量把耗時的操作放到子線程
8.文本處理(尺寸計算、繪制)
9.圖片處理(解碼仪吧、繪制)
GPU優(yōu)化策略:
1.盡量避免短時間內(nèi)大量圖片的顯示庄新,盡可能將多張圖片合成一張進行顯示
2.GPU能處理的最大紋理尺寸是4096x4096,一旦超過這個尺寸薯鼠,就會占用3.CPU資源進行處理择诈,所以紋理盡量不要超過這個尺寸
4.盡量減少視圖數(shù)量和層次
5.減少透明的視圖(alpha<1),不透明的就設(shè)置opaque為YES
6.盡量避免出現(xiàn)離屏渲染
離屏渲染
在OpenGL中出皇,GPU有2種渲染方式
On-Screen Rendering:當前屏幕渲染羞芍,在當前用于顯示的屏幕緩沖區(qū)進行渲染操作
Off-Screen Rendering:離屏渲染,在當前屏幕緩沖區(qū)以外新開辟一個緩沖區(qū)進行渲染操作
離屏渲染消耗性能的原因:
1.需要創(chuàng)建新的緩沖區(qū)
2.離屏渲染的整個過程郊艘,需要多次切換上下文環(huán)境荷科,先是從當前屏幕(On-Screen)切換到離屏(Off-Screen)唯咬;等到離屏渲染結(jié)束以后,將離屏緩沖區(qū)的渲染結(jié)果顯示到屏幕上畏浆,又需要將上下文環(huán)境從離屏切換到當前屏幕
哪些操作會觸發(fā)離屏渲染胆胰?
- 光柵化,layer.shouldRasterize = YES
- 遮罩刻获,layer.mask
- 圓角蜀涨,同時設(shè)置layer.masksToBounds = YES、layer.cornerRadius大于0
考慮通過CoreGraphics繪制裁剪圓角蝎毡,或者叫美工提供圓角圖片 - 陰影厚柳,layer.shadowXXX
如果設(shè)置了layer.shadowPath就不會產(chǎn)生離屏渲染
卡頓檢測
我們平時所說的“卡頓”主要是因為在主線程執(zhí)行了比較耗時的操作
如何檢測?
可以添加Observer到主線程RunLoop中沐兵,通過監(jiān)聽RunLoop狀態(tài)切換的耗時别垮,以達到監(jiān)控卡頓的目的
當然網(wǎng)上還有更多的別的方案,后續(xù)我會針對這一塊進行講解痒筒,讀者可以留言別的方式交流
3.安裝包體積瘦身
首先我們要知道安裝包的組成成分
- 可執(zhí)行文件
- 資源(圖片宰闰、音頻、視頻等)
資源瘦身方案:
- 采取無損壓縮簿透,進行資源壓縮
- 定期刪除無用資源移袍,這里推薦一個工具
[檢測無用資源](https://github.com/tinymind/LSUnusedResources)
可執(zhí)行文件瘦身方案:
- 編譯器優(yōu)化
Strip Linked Product、Make Strings Read-Only老充、Symbols Hidden by Default設(shè)置為YES
去掉異常支持葡盗,Enable C++ Exceptions、Enable Objective-C Exceptions設(shè)置為NO啡浊, Other C Flags添加-fno-exceptions - 利用AppCode(https://www.jetbrains.com/objc/)檢測未使用的代碼:菜單欄 -> Code -> Inspect Code
- 編寫LLVM插件檢測出重復(fù)代碼觅够、未被調(diào)用的代碼
4.App的電量消耗優(yōu)化
首先我們要知道App好點的幾個主要來源
- CPU
- 網(wǎng)絡(luò)請求任務(wù)
- 定位
- 圖片處理
我們大概從以下入手進行優(yōu)化,(視自己項目情況而定):
1.盡可能降低CPU巷嚣、GPU功耗
2.盡可能少用定時器
3.優(yōu)化I/O操作
1.盡量不要頻繁寫入小數(shù)據(jù)喘先,最好批量一次性寫入
2.讀寫大量重要數(shù)據(jù)時,考慮用dispatch_io廷粒,其提供了基于GCD的異步操作文件I/O的API窘拯。用dispatch_io系統(tǒng)會優(yōu)化磁盤訪問
3.數(shù)據(jù)量比較大的,建議使用數(shù)據(jù)庫(比如SQLite坝茎、CoreData)
4.網(wǎng)絡(luò)優(yōu)化
1.減少涤姊、壓縮網(wǎng)絡(luò)數(shù)據(jù)
2.如果多次請求的結(jié)果是相同的,盡量使用緩存
3.使用斷點續(xù)傳嗤放,否則網(wǎng)絡(luò)不穩(wěn)定時可能多次傳輸相同的內(nèi)容
4.網(wǎng)絡(luò)不可用時思喊,不要嘗試執(zhí)行網(wǎng)絡(luò)請求
5.讓用戶可以取消長時間運行或者速度很慢的網(wǎng)絡(luò)操作,設(shè)置合適的超時時間
批量傳輸次酌,比如恨课,下載視頻流時舆乔,不要傳輸很小的數(shù)據(jù)包,直接下載整個文件或者一大塊一大塊地下載庄呈。如果下載廣告蜕煌,一次性多下載一些,然后再慢慢展示诬留。如果下載電子郵件斜纪,一次下載多封,不要一封一封地下載
5.定位優(yōu)化
1.如果只是需要快速確定用戶位置文兑,最好用CLLocationManagerrequestLocation方法盒刚。定位完成后,會自動讓定位硬件斷電
2.如果不是導(dǎo)航應(yīng)用绿贞,盡量不要實時更新位置因块,定位完畢就關(guān)掉定位服務(wù)
3.盡量降低定位精度,比如盡量不要使用精度最高的kCLLocationAccuracyBest
需要后臺定位時籍铁,盡量設(shè)置pausesLocationUpdatesAutomatically為YES涡上,如果用戶不太可能移動的時候系統(tǒng)會自動暫停位置更新
4.盡量不要使用startMonitoringSignificantLocationChanges,優(yōu)先考慮startMonitoringForRegion:
6.硬件檢測優(yōu)化
用戶移動拒名、搖晃吩愧、傾斜設(shè)備時,會產(chǎn)生動作(motion)事件增显,這些事件由加速度計雁佳、陀螺儀、磁力計等硬件檢測同云。在不需要檢測的場合糖权,應(yīng)該及時關(guān)閉這些硬件
結(jié)尾
到這里,對app的優(yōu)化就基本說完了炸站,大家可以留言交流更好的優(yōu)化方案星澳,文章如有錯誤或者理解不到位之處,希望大家指點旱易,有幫助的老鐵們募判,點個喜歡,謝謝
Github: https://github.com/shLuckySeven