如何優化 App 的啟動耗時?

原文:iOS面試題大全

iOS 的 App 啟動主要分為以下步驟:

  • 打開 App,系統內核進行初始化跳轉到 dyld 執行。這個過程包括這些步驟:1)分配虛擬內存空間;2)fork 進程;3)加載 MachO (自身所有的可執行 MachO 文件的集合)到進程空間;4)加載動態鏈接器 dyld 并將控制權交給 dyld 處理。在這個過程中內核會產生 ASLR(Address space layout randomization) 隨機數值,這個值用于加載的 MachO 起始地址在內存中的偏移,隨機的地址可防止 MachO 代碼掃描并被 hack,提升安全性。通過 ASLR 雖然可隨機化各內存區基地址,但無法將程序內的代碼段和數據段隨機化,如果繞過(bypass) ASLR 依然可進行篡改,就需要結合 PIE(Position Independent Executable) 共同使用。與之相似的還有 PIC(Position Independent Code),位置無關代碼,作用于共享庫代碼。PIE/PIC 技術需要在編譯階段開啟。顧名思義,PIC 可將程序代碼裝載到任意地址,這樣就內部的指針不能靠固定的絕對地址訪問,而通過相對地址指令如 adrp 來獲取代碼和數據。
  • 進入 dyld 動態鏈接器,它負責將一個 App 處理為一個可運行的狀態,包含:
  • 加載 MachO 的依賴庫(這些依賴庫也是 MachO 格式的文件)。dyld 從可執行 MachO 文件的依賴開始, 遞歸加載所有依賴的動態庫。 動態庫包括:iOS 中用到的所有系統動態庫:加載 OC runtime 方法的 libobjc,系統級別的 libSystem(例如 libdispatch(GCD) 和 libsystem_blocks(Block));其他 App 自己的動態庫。根據 Apple 的描述,大部分 App 所加載的庫在 100~400 個。不過 iOS 系統庫已經被特殊優化過,如提前加入共享緩存,提前做好地址修正等。
  • Fix-ups(地址修正),包括 rebasing 和 binding 等。ASLR + PIE 技術增強了程序的安全性,使得依賴固定地址進行攻擊的方法失效,但也增加了程序自身的復雜度,MachO 文件的 rebase 和 bind info 等部分以及啟動時的 fix-ups 地址修正階段就是配合它而產生的。
  • ObjC 環境配置。經過了 MachO 程序和依賴庫的加載以及地址修正之后,dyld 所做的大部分事情已經完成了。在這一階段,dyld 開始對主程序的依賴庫進行初始化工作,而初始化的執行部分會回調到依賴庫內部執行,如 ObjC 的運行時環境所在的 libobjc.A.dylib 以及 libdispatch.dylib 等。ObjC Setup 的過程,主要是對 ObjC 數據進行關聯注冊:1)dyld 將主程序 MachO 基址指針和包含的 ObjC 相關類信息傳遞到 libobjc;2)ObjC Runtime 從 __DATA 段中獲取 ObjC 類信息,由于 ObjC 是動態語言,可以通過類名獲取其實例,所以 Runtime 維護了一個映射所有類的全局類名表。當加載的數據包含了類的定義,類的名字就需要注冊到全局表中;3)獲取 protocol、category 等類相關屬性并與對應類進行關聯;4)ObjC 的調用都是基于 selector 的,所以需要對 selector 全局唯一性進行處理。以上步驟由 dyld 啟動 libSystem.dylib 統一對基礎庫進行調用執行,這里面就包含了 libobjc 的 Runtime,同時 Runtime 會在 dyld 綁定回調,當 dyld 處理完相關數據后就會調用 ObjC Runtime 執行 Setup 工作。
  • 執行各模塊初始化器。從這一步就開始接近上(業務)層:1)通過 ObjC Runtime 在 dyld 注冊的通知,當 MachO 鏡像準備完畢后,dyld 會回調到 ObjC 中執行 +load() 方法,包括以下步驟:a)獲取所有 non-lazy class 列表;b)按繼承以及 category 的順序將類排入待加載列表;c)對待加載列表中的類進行方法判斷并調用 +load() 方法。2)執行 C/C++ 初始化構造器,如通過 attribute((constructor)) 注解的函數。3)如果包含 C++,則 dyld 同樣會回調到 libc++ 庫中對全局靜態變量、隱式初始化等進行調用。
  • 查找并跳轉到 main() 函數入口。到了最后,dyld 回到 Load command,找到 LC_MAIN,拿到 entryoff 再加上 MachO 在內存的加載首地址(首地址就是內核傳來的 slide 偏移)就得到了 main() 的入口地址,從而進入我們顯式的程序邏輯。

進入 main() -> UIApplicationMain -> 初始化回調 -> 顯示UI。

iOS 的 App 啟動時長大概可以這樣計算:

t(App 總啟動時間) = t1(main 調用之前的加載時間) + t2(main 調用之后的加載時間)。

t1 = 系統 dylib(動態鏈接庫)和自身 App 可執行文件的加載。

t2 = main 方法執行之后到 AppDelegate 類中的 application:didFinishLaunchingWithOptions:方法執行結束前這段時間,主要是構建第一個界面,并完成渲染展示。

在 t1 階段加快 App 啟動的建議:

  • 盡量使用靜態庫,減少動態庫的使用,動態鏈接比較耗時。
  • 如果要用動態庫,盡量將多個 dylib 動態庫合并成一個。
  • 盡量避免對系統庫使用 optional linking,如果 App 用到的系統庫在你所有支持的系統版本上都有,就設置為 required,因為 optional 會有些額外的檢查。
  • 減少 Objective-C Class、Selector、Category 的數量。可以合并或者刪減一些 OC 類。
  • 刪減一些無用的靜態變量,刪減沒有被調用到或者已經廢棄的方法。
  • 將不必須在 +load 中做的事情盡量挪到 +initialize 中,+initialize 是在第一次初始化這個類之前被調用,+load 在加載類的時候就被調用。盡量將 +load 里的代碼延后調用。
  • 盡量不要用 C++ 虛函數,創建虛函數表有開銷。
  • 不要使用 __atribute__((constructor)) 將方法顯式標記為初始化器,而是讓初始化方法調用時才執行。比如使用 dispatch_once()pthread_once() std::once()
  • 在初始化方法中不調用 dlopen()dlopen() 有性能和死鎖的可能性。
  • 在初始化方法中不創建線程。

在 t2 階段加快 App 啟動的建議:

  • 盡量不要使用 xib/storyboard,而是用純代碼作為首頁 UI。
  • 如果要用 xib/storyboard,不要在 xib/storyboard 中存放太多的視圖。
  • application:didFinishLaunchingWithOptions: 里的任務盡量延遲加載或懶加載。
  • 不要在 NSUserDefaults 中存放太多的數據,NSUserDefaults 是一個 plist 文件,plist 文件被反序列化一次。
  • 避免在啟動時打印過多的 log。
  • 少用 NSLog,因為每一次 NSLog 的調用都會創建一個新的 NSCalendar 實例。
  • 每一段 SQLite 語句都是一個段被編譯的程序,調用 sqlite3_prepare 將編譯 SQLite 查詢到字節碼,使用 sqlite_bind_int 綁定參數到 SQLite 語句。
  • 為了防止使用 GCD 創建過多的線程,解決方法是創建串行隊列, 或者使用帶有最大并發數限制的 NSOperationQueue。
  • 線程安全:UIKit只能在主線程執行,除了 UIGraphics、UIBezierPath 之外,UIImage、CG、CA、Foundation 都不能從兩個線程同時訪問。
  • 不要在主線程執行磁盤、網絡、Lock 或者 dispatch_sync、發送消息給其他線程等操作。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/536916.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/536916.shtml
英文地址,請注明出處:http://en.pswp.cn/news/536916.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

windows qt 不能debug_linux配置vlc-qt

vlc-qt 是基于vlc庫,用于開發音頻視頻應用,性能優秀。vlc-qt/vlc-qt?github.com使用vlc-qt首先需要編譯vlc-qt (windows可以下載使用編譯好的,但是只能用在release模式)(在windows系統中)使用w…

idou老師教你學Istio 27:解讀Mixer Report流程

1、概述 Mixer是Istio的核心組件,提供了遙測數據收集的功能,能夠實時采集服務的請求狀態等信息,以達到監控服務狀態目的。 1.1 核心功能 ?前置檢查(Check):某服務接收并響應外部請求前,先通過E…

mysql刪除密碼代碼_mysql 用戶新建、受權、刪除、密碼修改

mysql 用戶新建、授權、刪除、密碼修改首先要聲明一下:一般情況下,修改MySQL密碼,授權,是需要有mysql里的root權限的。注:本操作是在WIN命令提示符下,phpMyAdmin同樣適用。用戶:phplamp 用戶數…

KindEditor 上傳漏洞致近百個黨政機關網站遭植入

開發四年只會寫業務代碼,分布式高并發都不會還做程序員? >>> 2月21日消息,近日,安恒明鑒網站安全監測平臺和應急響應中心監測發現近百起黨政機關網站被植入色情廣告頁面,分析發現被植入色情廣告頁面的網站都…

php mysql登陸頁面完整代碼_求助:PHP實現登陸注冊的代碼是什么啊(主要是數據庫那塊)?...

思路:注冊:獲取前臺表單數據->數據庫連接->判斷數據是否存在,存在輸出提示,不存在則向數據庫插入表單傳來的值->如果sql執行失敗輸出錯誤,成功功輸出注冊成功登陸:獲取前臺表單數據->數據庫連接…

Insql 1.8.2 發布,輕量級 .NET ORM 類庫

開發四年只會寫業務代碼,分布式高并發都不會還做程序員? >>> Insql 是一個輕量級的.NET ORM 類庫。對象映射基于 Dapper, Sql 配置靈感來自于 Mybatis。 TA 的追求:簡潔、優雅、性能與質量 TA 的宗旨:讓你用起來感覺到…

python 函數中所有print保存csv_python for循環print怎樣才能輸出csv呢

import csv,redef search(req,line):text re.search(req,line)if text:data text.group(1)else:data noreturn datacsvfile file(serp_html.csv,rb)reader csv.reader(csvfile)輸出百度搜索結果數據:當前關鍵詞,排名,排名網站&#xff0…

java中具有繼承關系的類及其對象初始化順序

先說結論對于具有繼承關系的類,它們的類和對象構造順序為:父類的類構造器() -> 子類的類構造器() -> 父類成員變量的賦值和實例代碼塊 -> 父類的構造函數 -> 子類成員變量的賦值和實例代碼塊 -> 子類的構造函數。 實驗代碼如下&#xff1…

mysql varchar 2000能存_mysql 數據庫 varchar 到底可以存多少數據呢,長文慎入

一、關于UTF-8 UTF-8 Unicode Transformation Format-8bit。是用以解決國際上字符的一種多字節編碼。 它對英文使用8位(即一個字節),中文使用24位(三個字節)來編碼。 UTF-8包含全世界所有國家需要用到的字符,是國際編碼,通用性強。 UTF-8編碼…

教程 | 如何利用C++搭建個人專屬的TensorFlow

在開始之前,首先看一下最終成型的代碼: 分支與特征后端(https://github.com/OneRaynyDay/autodiff/tree/eigen)僅支持標量的分支(https://github.com/OneRaynyDay/autodiff/tree/master)這個項目是我與 Min…

docker kali安裝mysql_kali安裝docker(有效詳細的教程) ——vulhub漏洞復現 001

前記:博主有著多次安裝docker的豐富經驗,曾經為了在kali成功安裝docker花費不少時間。在kali2016.3一直到最新的kali2019.4都通吃!所以跟著下面的步驟走,絕對不會出錯。(該機子此前沒裝過docker,并且配置好了kali更新源…

PDF文件如何轉成markdown格式

百度上根據pdf轉makrdown為關鍵字進行搜索,結果大多數是反過來的轉換,即markdown文本轉PDF格式。 但是PDF轉markdown的解決方案很少。 正好我工作上有這個需求,所以自己實現了一個解決方案。 下圖是一個用PDF XChange Editor打開的PDF文件&am…

kangle支不支持PHP_【轉載】PHP調用kangle的API

摘要:根據管理的API公布寫了一個類封裝了一個操作集合,這是一個kangleAPI的一個封...根據管理的API公布寫了一個類封裝了一個操作集合,這是一個kangleAPI的一個封裝吧,是在其他地方看到的,接口包含獲取easypanel的信息…

ES6 學習筆記(一)let,const和解構賦值

let和const let和const是es6新增的兩個變量聲明關鍵字,與var的不同點在于: (1)let和const都是塊級作用域,在{}內有效,這點在for循環中非常有用,只在循環體內有效。var為函數作用域。 &#xff0…

mysql數據庫容量和性能_新品速遞丨容量盤性能提升超 300%,數據庫支持 MySQL 8.0...

2關系型數據庫 MySQL Plus支持 MySQL 8.0 內核及 XtraBackup 物理在線遷移方式關系型數據庫服務 MySQL Plus 發布新版本 1.0.6 , 新增多項功能,提升了集群自動化運維能力。主要升級有:- 支持 MySQL 8.0 內核:根據官方測試&#xf…

10. Python面向對象

Python從設計之初就已經是一門面向對象的語言,正因為如此,在Python中創建一個類和對象是很容易的。如果接觸過java語言同學應該都知道,Java面向對象三大特征是:封裝、繼承、多態。Python面向對象也有一些特征,接下來我…

mysql聚簇索引 和主鍵的區別_[MySQL] innoDB引擎的主鍵與聚簇索引

MysqL的innodb引擎本身存儲的形式就必須是聚簇索引的形式,在磁盤上樹狀存儲的,但是不一定是根據主鍵聚簇的,有三種情形:1. 有主鍵的情況下,主鍵就是聚簇索引2. 沒有主鍵的情況下,第一個非空null的唯一索引就是聚簇索引3. 如果上面都沒有,那么就是有一個隱藏的row-id作為聚簇索引…

前端頁面:一直報Cannot set property 'height' of undefined

1、出現錯誤的例子,只拷貝了項目中關鍵出現問題的部分 例子中明明寫了styleheight:16px這個屬性,但是為什么還說height未定義呢 通過打印發現:cks.each(function () { autoTextAreaHeight($(this)); });中的$(this)取出來…

mysql表在線轉成分區表_11g普通表在線轉換分區表

本帖最后由 燈和樹 于 2016-5-4 14:58 編輯由于業務系統數據量增大,對其用戶表在線完成分區表轉換過程,記錄如下,11g數據庫支持。創建過渡分區表根據USER_ID創建分區表CREATE TABLE SDP_SMECD.TEST_T_USER_ID(USER_ID NUMBER(13) …

tiger4444/rabbit4444后綴勒索病毒怎么刪除 能否百分百恢復

上海某客戶中了tiger4444的勒索病毒,找到我們后,一天內全部恢復完成。說了很多關于勒索病毒的事情,也提醒過大家,可總是有人疏忽,致使中招后,丟錢丟面子,還丟工作。 那么要怎樣預防呢與處理呢&a…