一、App啟動優化
1.App的啟動可以分為2種
- 冷啟動(Cold Launch):從零開始啟動APP
- 熱啟動(Warm Launch):APP已經在記憶體中,在后臺存活著,再次點擊圖示啟動APP
- APP啟動時間的優化,主要是針對冷啟動進行優化
- 通過添加環境變數可以列印出APP的啟動時間分析(Edit scheme -> Run -> Arguments) DYLD_PRINT_STATISTICS設定為 1
- 如果需要更詳細的資訊,那就將DYLD_PRINT_STATISTICS_DETAILS設定為1
2.App 冷啟動分為四大階段
- dyld 加載可執行檔案,動態庫(遞回加載)
- runtime
- main() 函式執行后
- 首屏渲染完成后
一個開發者,有一個學習的氛圍跟一個交流圈子特別重要,這是一個我的iOS交流群:1012951431, 分享BAT,阿里面試題、面試經驗,討論技術, 大家一起交流學習成長!希望幫助開發者少走彎路,
2.1關于dyld
-
在Mac 、iOS中,是使用了/usr/lib/dyld程式來加載動態庫
-
dynamic link editor,動態鏈接編輯器
-
dynamic loader,動態加載器
-
dyld 的原始碼 https://opensource.apple.com/tarballs/dyld/
-
initializeMainExecutable 方法開始的.dyld會優先初始化動態庫,然后初始化App的可執行檔案,
-
用MachOView (https://github.com/gdbinit/MachOView)查看加載程序如上圖
( 備注1: 如果設定了 DYLD_PRINT_LIBRARIES,或者選中run/diagnostics 下面的 dynamic library loads 那么 dyld將會列印出什么庫被加載了
? 備注2:DYLD_PRINT_STATISTICS_DETAILS 列印啟動時間
? 備注3:dyly還可以抽取蘋果原生庫 方法: 1: launch-cache/dsc_extractor.cpp檔案中 把#if(0) 以及之前的都洗掉,#endif也洗掉 2:編譯clang++ -o dsc_extractor dsc_extractor.cpp 生成可執行檔案 3:./dsc_extractor dyld_shared_cache_armv7s armv7s 進行抽取 )
2.2 runtime
? 原始碼: https://opensource.apple.com/source/objc4/ 原始碼分析可參考:https://www.jianshu.com/p/3019605a4fc9
? 啟動APP時,runtime所做的事情有
- 呼叫map_images進行可執行檔案內容的決議和處理
- 在load_images中呼叫call_load_methods,呼叫所有Class和Category的+load方法 進行各種objc結構的初始化(注冊Objc類 、初始化類物件等等)
- 呼叫C++靜態初始化器和attribute((constructor))修飾的函式
- 到此為止,可執行檔案和動態庫中所有的符號(Class,Protocol,Selector,IMP,…)都已經按格式成功加載到記憶體中,被 runtime 所管理
關于load和initialize 可參考iOS中load和initialize一文詳細分析
2.3main函式執行后
? main() 函式執行后的階段,指的是從 main() 函式執行開始,到 appDelegate 的 didFinishLaunchingWithOptions 方法里首屏渲染相關方法執行完成,
- 首屏初始化所需組態檔的讀寫操作
- 首屏串列大資料的讀取
- 首屏渲染的大量計算等
總結:
APP的啟動由dyld主導,將可執行檔案加載到記憶體,順便加載所有依賴的動態庫, 并由runtime負責加載成objc定義的結構,所有初始化作業結束后,dyld就會呼叫main函式, 接下來就是UIApplicationMain函式,AppDelegate的application:didFinishLaunchingWithOptions:方法
3.App啟動優化
? 按照不同的階段
-
dyld
- 減少動態庫、合并一些動態庫(定期清理不必要的動態庫),減少動態庫加載,每個庫本身都有依賴關系,蘋果公司建議使用更少的動態庫,蘋果最多支持6個非系統的動態庫合并為一個,
- 減少Objc類、分類的數量、減少Selector數量(定期清理不必要的類、分類)
- 減少C++虛函式數量, 減少C++全域變數的數量
- Swift盡量使用struct
- runtime
- 用+initialize方法和dispatch_once取代所有的attribute((constructor))、C++靜態構造器、ObjC的+load,因為在一個+load()方法里,運行時進行方法替換操作會帶來4毫秒的損耗,
- main() 函式執行后
- 功能級別的優化:main()函式開始執行后到首屏渲染完成前,只處理首屏相關的業務,其他的非首屏業務的初始化,監聽注冊,組態檔讀取放在首屏渲染完成后去做
- ReactiveCocoa創建一個信號6毫秒,+load()執行一次,4毫秒
- 檢測App耗時
- 抓取主執行緒的方法呼叫堆疊,計算一段時間各個方法的耗時,Xcode自帶的Time Profiler
- 對objc_msgSend方法進行hook來掌握所有方法的執行耗時 objc_msgSend原始碼 https://opensource.apple.com/source/objc4/objc4-723/runtime/Messengers.subproj/
- fackbook開源了fishhook的代碼https://github.com/facebook/fishhook 其大致思路為:通過重新系結符號,實作對c方法的hook,dyld是通過更新Mach-O二進制的_DATA segment特定的部分中的指標來系結lazy和non-lazy符號,通過確認傳遞給rebind_symbol里每個符號更新的位置,就可以找出替換來重新系結這些符號,
- 在不影響用戶體驗的前提下,盡可能將一些操作延遲,不要全部都放在finishLaunching方法中 按需加載
- 不使用xib,直接視用代碼加載首頁視圖
- NSUserDefaults實際上是在Library檔案夾下會生產一個plist檔案,如果檔案太大的話一次能讀取到記憶體中可能很耗時,這個影響需要評估,如果耗時很大的話需要拆分(需考慮老版本覆寫安裝兼容問題)
- 每次用NSLog方式列印會隱式的創建一個Calendar,因此需要刪減啟動時各業務方打的log,或者僅僅針對內測版輸出log
- 梳理應用啟動時發送的所有網路請求,是否可以統一在異步執行緒請求
二、安裝包瘦身
1、安裝包(IPA)主要由可執行檔案、資源組成
- 資源(圖片、音頻、視頻等)
- 采取無損壓縮
- 去除沒有用到的資源: https://github.com/tinymind/LSUnusedResources
2、 可執行檔案瘦身
.1 編譯器優化
-
Strip Linked Product、Make Strings Read-Only、Symbols Hidden by Default設定為YES
-
去掉例外支持,Enable C++ Exceptions、Enable Objective-C Exceptions設定為NO, Other C Flags添加-fno-exceptions
2.2利用AppCode
https://www.jetbrains.com/objc/)檢測未使用的代碼:選單欄 -> Code -> Inspect Code
2. 3撰寫LLVM插件檢測出重復代碼、未被呼叫的代碼
2.4 生成LinkMap檔案,可以查看可執行檔案的具體組成
2.5 可借助第三方工具決議LinkMap檔案: https://github.com/huanxsd/LinkMap
三、卡頓問題
3.1、CPU 和GPU
-
CPU (Central Processing Unit,中央處理器)
物件的創建和銷毀、物件屬性的調整、布局計算、文本的計算和排版、圖片的格式轉換和解碼、影像的繪制(Core Graphics)
-
GPU (Graphics Processing Unit,圖形處理器)
紋理的渲染
-
在iOS中是雙緩沖機制,有前幀快取、后幀快取
3.2優化方向
- 盡可能減少CPU、GPU資源消耗
- 盡量用輕量級的物件,比如用不到事件處理的地方,可以考慮使用CALayer取代UIView
- 不要頻繁地呼叫UIView的相關屬性,比如frame、bounds、transform等屬性,盡量減少不必要的修改
- 盡量提前計算好布局,在有需要時一次性調整對應的屬性,不要多次修改屬性
- Autolayout會比直接設定frame消耗更多的CPU資源
- 圖片的size最好剛好跟UIImageView的size保持一致
- 控制一下執行緒的最大并發數量
- 盡量避免短時間內大量圖片的顯示,盡可能將多張圖片合成一張進行顯示
- GPU能處理的最大紋理尺寸是4096x4096,一旦超過這個尺寸,就會占用CPU資源進行處理,所以紋理盡量不要超過這個尺寸
- 盡量減少視圖數量和層次
- 減少透明的視圖(alpha<1),不透明的就設定opaque為YES
- 盡量把耗時的操作放到子執行緒
- 文本處理(尺寸計算、繪制) p
- 圖片處理(解碼、繪制)
)3.3、離屏渲染
- 盡量避免出現離屏渲染
- 在OpenGL中,GPU有2種渲染方式
- On-Screen Rendering:當前螢屏渲染,在當前用于顯示的螢屏緩沖區進行渲染操作
- Off-Screen Rendering:離屏渲染,在當前螢屏緩沖區以外新開辟一個緩沖區進行渲染操作
- 離屏渲染消耗性能的原因
- 需要創建新的緩沖區
- 離屏渲染的整個程序,需要多次切換背景關系環境,先是從當前螢屏(On-Screen)切換到離屏(Off-Screen);等到離屏渲染結束以后,將離屏緩沖區的渲染結果顯示到螢屏上,又需要將背景關系環境從離屏切換到當前螢屏
- 哪些操作會觸發離屏渲染?
- 光柵化,layer.shouldRasterize = YES
- 遮罩,layer.mask
- 圓角,同時設定layer.masksToBounds = YES、layer.cornerRadius大于0(考慮通過CoreGraphics繪制裁剪圓角,或者叫UI提供圓角圖片)
- 陰影,layer.shadowXXX (如果設定了layer.shadowPath就不會產生離屏渲染)
記憶體泄露
一、查找泄漏點 (兩種工具)
?
- 1 > Analyze
- 學 名: 靜態分析工具- 查 找: 可以通過 Product ->Analyze 選單項啟動- 快捷鍵: CMD+shift +b.- Analyze主要分析以下四種問題:
1) 邏輯錯誤:訪問空指標或未初始化的變數等;
2) 記憶體管理錯誤:如記憶體泄漏等;
3) 宣告錯誤:從未使用過的變數;
4) Api呼叫錯誤:未包含使用的庫和框架,
- 2 >Instruments
- 學 名: 動態分析工具- 查 找: Product ->Profile 選單項啟動- 快捷鍵: CMD + i.
簡 介:它有很多跟蹤模塊可以動態分析和跟蹤記憶體, CPU 和檔案系統.
四、耗電優化
-
盡可能降低CPU、GPU功耗
-
少用定時器
-
優化I/O操作
- 盡量不要頻繁寫入小資料,最好批量一次性寫入
- 讀寫大量重要資料時,考慮用dispatch_io,其提供了基于GCD的異步操作檔案I/O的API,用dispatch_io系統會優化磁盤訪問
- 資料量比較大的,建議使用資料庫(比如SQLite、CoreData)
-
網路優化
- 減少、壓縮網路資料
- 如果多次請求的結果是相同的,盡量使用快取
- 使用斷點續傳,否則網路不穩定時可能多次傳輸相同的內容
- 網路不可用時,不要嘗試執行網路請求
- 讓用戶可以取消長時間運行或者速度很慢的網路操作,設定合適的超時時間
- 批量傳輸,比如,下載視頻流時,不要傳輸很小的資料包,直接下載整個檔案或者一大塊一大塊地下載,如果下載廣告,一 次性多下載一些,然后再慢慢展示,如果下載電子郵件,一次下載多封,不要一封一封地下載
-
定位優化
- 如果只是需要快速確定用戶位置,最好用CLLocationManager的requestLocation方法,定位完成后,會自動讓定位硬體斷電
- 如果不是導航應用,盡量不要實時更新位置,定位完畢就關掉定位服務
- 盡量降低定位精度,比如盡量不要使用精度最高的kCLLocationAccuracyBest
- 需要后臺定位時,盡量設定pausesLocationUpdatesAutomatically為YES,如果用戶不太可能移動的時候系統會自動暫停位置更新
- 盡量不要使用startMonitoringSignificantLocationChanges,優先考慮startMonitoringForRegion:
-
用戶移動、搖晃、傾斜設備時,會產生動作(motion)事件,這些事件由加速度計、陀螺儀、磁力計等硬體檢測,在不需要檢測的場合,應該及時關閉這些硬體
另外,如果你想一起進階,不妨添加一下交流群1012951431,選擇加入一起交流,一起學習,期待你的加入!
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/4165.html
標籤:iOS
下一篇:iOS組件化開發-發布私有庫
