ios啟動優(yōu)化

夕陽最美時本谜,也總是將近黃昏初家。
世上有很多事都是這樣子的,尤其是一些特別輝煌美好的事乌助。
所以你不必傷感溜在,也不用惋惜,縱然到江湖去趕上了春他托,也不必留住它掖肋。
因為這就是人生,有些事你留也留不住赏参。
你一定要先學(xué)會忍受它的無情志笼,才會懂得享受它的溫柔。

所以該靜心擼碼的時候把篓,就不要想其他纫溃。好了,廢話少說纸俭,直接切入主題皇耗。

1. App啟動過程

解析Info.plist

  • 加載相關(guān)信息南窗,例如如閃屏
  • 沙箱建立揍很、權(quán)限檢查

Mach-O加載

  • 如果是胖二進制文件,尋找合適當前CPU類別的部分
  • 加載所有依賴的Mach-O文件(遞歸調(diào)用Mach-O加載的方法)
  • 定位內(nèi)部万伤、外部指針引用窒悔,例如字符串、函數(shù)等
  • 執(zhí)行聲明為attribute((constructor))的C函數(shù)
  • 加載類擴展(Category)中的方法
  • C++靜態(tài)對象加載敌买、調(diào)用ObjC的 +load 函數(shù)

程序執(zhí)行

  • 調(diào)用main()
  • 調(diào)用UIApplicationMain()
  • 調(diào)用applicationWillFinishLaunching

什么是冷啟動简珠、熱啟動

從電路角度來看:

熱啟動是在系統(tǒng)仍通電的情況下重新啟動系統(tǒng),熱啟動也是一次軟件復(fù)位。熱啟動清除易失性系統(tǒng)內(nèi)存聋庵,并重新裝載操作系統(tǒng)膘融。
冷啟動是用關(guān)閉電源來啟動系統(tǒng),冷啟動還對硬件進行復(fù)位祭玉,它檢查硬件氧映,并重新裝載操作系統(tǒng)。
最重要的是冷啟動對硬件進行一次檢查⊥鸦酰現(xiàn)在的電腦這個過程好像不是很明顯岛都,但是在40年前,這個硬件檢查一次可是很耗時間的振峻。
冷啟動臼疫,電路會從斷開變成通路,期間扣孟,主機受到的影響類似我們開電燈的時候電燈受的影響(我說的是類似)烫堤,大家都知道,電動設(shè)備啟動的時候會有一大電流沖擊凤价。

從移動app角度來看:

當用戶按下home鍵的時候塔逃,iOS的App并不會馬上被kill掉,還會繼續(xù)存活若干時間料仗。理想情況下湾盗,用戶點擊App的圖標再次回來的時候,App幾乎不需要做什么立轧,就可以還原到退出前的狀態(tài)格粪,繼續(xù)為用戶服務(wù)。這種持續(xù)存活的情況下啟動App氛改,我們稱為熱啟動帐萎,相對而言冷啟動就是App被kill掉以后一切從頭開始啟動的過程。我們這里只討論App冷啟動的情況胜卤。

image.png

測量Pre-main Time

在Xcode的菜單中選擇Project→Scheme→Edit Scheme...疆导,然后找到 Run → Environment Variables
配置的 key 為:DYLD_PRINT_STATISTICS 設(shè)置1或者YES都可。

image.png

勾選如圖:


image.png

運行的時候會進行打痈瘐铩:


image.png

what`s the fuck澈段?

main()函數(shù)之前總共使用了1.6ms
加載動態(tài)庫用了1.1ms,
指針重定位使用了392.11ms舰攒,

ObjC類初始化使用了46.43ms败富,
各種初始化使用了56.29ms。
在初始化耗費的56.29ms中摩窃,用時最多的初始化是libSystem.dylib兽叮、libMainThreadChecker.dylib

那么如何盡可能的減少pre-main花費的時間呢,主要就從輸出日志給出的四個階段下手:

  • 對動態(tài)庫加載的時間優(yōu)化
    每個App都進行動態(tài)庫加載,其中系統(tǒng)級別的動態(tài)庫占據(jù)了絕大數(shù),而針對系統(tǒng)級別的動態(tài)庫都是經(jīng)過系統(tǒng)高度優(yōu)化的,不用擔(dān)心時間的花費.開發(fā)者應(yīng)該關(guān)注于自己集成到App的那些動態(tài)庫,這也是最能消耗加載時間的地方.對此Apple建議減少在App里開發(fā)者的動態(tài)庫集成或者有可能地將其多個動態(tài)庫最終集成一個動態(tài)庫后進行導(dǎo)入, 盡量保證將App現(xiàn)有的非系統(tǒng)級的動態(tài)庫個數(shù)保證在6個以內(nèi).

  • 減少Appp的Objective-C類,分類和的唯一Selector的個數(shù)
    這樣做主要是為了加快程序的整個動態(tài)鏈接, 在進行動態(tài)庫的重定位和綁定(Rebase/binding)過程中減少指針修正的使用,加快程序機器碼的生成.

  • 減少Objc運行初始化的時間花費.
    主要是類的注冊,分類的注冊,唯一選擇器的存在,以及涉及子父類內(nèi)存布局的Non Fragile ivars偏移的更新,都會影響Objective-C運行時初始化的時間消耗.

  • 使用initialize方法進行必要的初始化工作.用+initialize方法替換調(diào)用原先在OC的+load方法中執(zhí)行初始代碼工作,從而加快所有類文件的加載速度.
    使用load不要在這里面執(zhí)行耗時的操作。其他的不是短時間能改變的。

測量main Time

一般項目的組織架構(gòu):


image.png

didFinishLaunchingWithOptions
didFinishLaunchingWithOptions這里面有的是必須執(zhí)行的鹦聪,但是我們可以適當?shù)母鶕?jù)功能的不同對應(yīng)的適當延遲啟動的時機账阻。對于我們項目,我將初始化分為三個類型:

  • 日志泽本、統(tǒng)計等必須在 APP 一起動就最先配置的事件
  • 項目配置宰僧、環(huán)境配置、用戶信息的初始化 观挎、推送琴儿、IM等事件
  • 其他 SDK 和配置事件

第一類,由于這類事件的特殊性嘁捷,所以必須第一時間啟動造成,仍然把它留在 didFinishLaunchingWithOptions 里啟動。
第二類事件雄嚣,這些功能在用戶進入 APP 主體的之前是必須要加載完的晒屎,所以我們可以把它放在第二批,也就是用戶已經(jīng)看到廣告頁面缓升,再進行廣告倒計時的時候再啟動鼓鲁。
第三類事件,由于不是必須的港谊,所以我們可以放在第一個界面渲染完成以后的 viewDidAppear 方法里骇吭,這里完全不會影響到啟動時間。

參考文章歧寺,我們不妨提取出一個工具類燥狰,為了以后防止以后繼續(xù)優(yōu)化

下面是這個類的頭文件:

/**
 * 注意: 這個類負責(zé)所有的 didFinishLaunchingWithOptions 延遲事件的加載.
 * 以后引入第三方需要在 didFinishLaunchingWithOptions 里初始化或者我們自己的類需要在 didFinishLaunchingWithOptions 初始化的時候,
 * 要考慮盡量少的啟動時間帶來好的用戶體驗, 所以應(yīng)該根據(jù)需要減少 didFinishLaunchingWithOptions 里耗時的操作.
 * 第一類: 比如日志 / 統(tǒng)計等需要第一時間啟動的, 仍然放在 didFinishLaunchingWithOptions 中.
 * 第二類: 比如用戶數(shù)據(jù)需要在廣告顯示完成以后使用, 所以需要伴隨廣告頁啟動, 只需要將啟動代碼放到 startupEventsOnADTimeWithAppDelegate 方法里.
 * 第三類: 比如直播和分享等業(yè)務(wù), 肯定是用戶能看到真正的主界面以后才需要啟動, 所以推遲到主界面加載完成以后啟動, 只需要將代碼放到 startupEventsOnDidAppearAppContent 方法里.
 */

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface BLDelayStartupTool : NSObject

/**
 * 啟動伴隨 didFinishLaunchingWithOptions 啟動的事件.
 * 啟動類型為:日志 / 統(tǒng)計等需要第一時間啟動的.
 */
+ (void)startupEventsOnAppDidFinishLaunchingWithOptions;

/**
 * 啟動可以在展示廣告的時候初始化的事件.
 * 啟動類型為: 用戶數(shù)據(jù)需要在廣告顯示完成以后使用, 所以需要伴隨廣告頁啟動.
 */
+ (void)startupEventsOnADTime;

/**
 * 啟動在第一個界面顯示完(用戶已經(jīng)進入主界面)以后可以加載的事件.
 * 啟動類型為: 比如直播和分享等業(yè)務(wù), 肯定是用戶能看到真正的主界面以后才需要啟動, 所以推遲到主界面加載完成以后啟動.
 */
+ (void)startupEventsOnDidAppearAppContent;

@end

NS_ASSUME_NONNULL_END

下面是 .m 文件,這里做了一層自動校驗斜筐,如果 30 秒 以后龙致,這些啟動項有沒有被啟動的,就會在 DEBUG 環(huán)境下彈出警告信息顷链。同時也會將那些沒有啟動的啟動項進行啟動目代。

#import "BLDelayStartupTool.h"

static BOOL _isCalledStartupEventsOnAppDidFinishLaunchingWithOptions = NO;
static BOOL _isCalledStartupEventsOnADTimeWithAppDelegate = NO;
static BOOL _isCalledStartupEventsOnDidAppearAppContent = NO;
const NSTimeInterval kBLDelayStartupEventsToolCheckCallTimeInterval = 30;
@implementation BLDelayStartupTool

+ (void)load {
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(kBLDelayStartupEventsToolCheckCallTimeInterval * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [self checkStartupEventsDidLaunched];
    });
}

+ (void)checkStartupEventsDidLaunched {
    NSString *alertString = @"";
    if (!_isCalledStartupEventsOnAppDidFinishLaunchingWithOptions) {
        alertString = [alertString stringByAppendingString:@"AppDidFinishLaunching, "];
        [self startupEventsOnAppDidFinishLaunchingWithOptions];
    }
    if (!_isCalledStartupEventsOnADTimeWithAppDelegate) {
        alertString = [alertString stringByAppendingString:@"ADTime, "];
        [self startupEventsOnADTime];
    }
    if (!_isCalledStartupEventsOnDidAppearAppContent) {
        alertString = [alertString stringByAppendingString:@"DidAppearAppContent"];
        [self startupEventsOnDidAppearAppContent];
    }

    if (alertString.length > 0) {

#if DEBUG
        alertString = [alertString stringByAppendingString:@" 等延遲啟動項沒有啟動, 這會造成應(yīng)用奔潰"];
        UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"注意" message:alertString delegate:nil cancelButtonTitle:@"好的" otherButtonTitles:nil];
        [alertView show];
#endif
    }
}

+ (void)startupEventsOnAppDidFinishLaunchingWithOptions {
    _isCalledStartupEventsOnAppDidFinishLaunchingWithOptions = YES;
}

+ (void)startupEventsOnADTime {
    _isCalledStartupEventsOnADTimeWithAppDelegate = YES;
}

+ (void)startupEventsOnDidAppearAppContent {
    _isCalledStartupEventsOnDidAppearAppContent = YES;
}

@end

參考文章:
一次立竿見影的啟動時間優(yōu)化
WWDC 之優(yōu)化 App 啟動速度
App Startup Time: Past, Present, and Future
iOS App 啟動性能優(yōu)化
優(yōu)化 App 的啟動時間
iOS 啟動優(yōu)化 + 監(jiān)控實踐

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市嗤练,隨后出現(xiàn)的幾起案子榛了,更是在濱河造成了極大的恐慌,老刑警劉巖潭苞,帶你破解...
    沈念sama閱讀 206,013評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異此疹,居然都是意外死亡,警方通過查閱死者的電腦和手機蝗碎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,205評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蹦骑,“玉大人,你說我怎么就攤上這事眠菇。” “怎么了捎废?”我有些...
    開封第一講書人閱讀 152,370評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長登疗。 經(jīng)常有香客問我,道長辐益,這世上最難降的妖魔是什么断傲? 我笑而不...
    開封第一講書人閱讀 55,168評論 1 278
  • 正文 為了忘掉前任认罩,我火速辦了婚禮,結(jié)果婚禮上续捂,老公的妹妹穿的比我還像新娘。我一直安慰自己疾忍,他們只是感情好,可當我...
    茶點故事閱讀 64,153評論 5 371
  • 文/花漫 我一把揭開白布一罩。 她就那樣靜靜地躺著杨幼,像睡著了一般。 火紅的嫁衣襯著肌膚如雪聂渊。 梳的紋絲不亂的頭發(fā)上差购,一...
    開封第一講書人閱讀 48,954評論 1 283
  • 那天,我揣著相機與錄音汉嗽,去河邊找鬼欲逃。 笑死,一個胖子當著我的面吹牛饼暑,可吹牛的內(nèi)容都是我干的稳析。 我是一名探鬼主播洗做,決...
    沈念sama閱讀 38,271評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼彰居!你這毒婦竟也來了诚纸?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,916評論 0 259
  • 序言:老撾萬榮一對情侶失蹤陈惰,失蹤者是張志新(化名)和其女友劉穎畦徘,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體抬闯,經(jīng)...
    沈念sama閱讀 43,382評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡井辆,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,877評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了溶握。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片杯缺。...
    茶點故事閱讀 37,989評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖奈虾,靈堂內(nèi)的尸體忽然破棺而出夺谁,到底是詐尸還是另有隱情,我是刑警寧澤肉微,帶...
    沈念sama閱讀 33,624評論 4 322
  • 正文 年R本政府宣布匾鸥,位于F島的核電站,受9級特大地震影響碉纳,放射性物質(zhì)發(fā)生泄漏勿负。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,209評論 3 307
  • 文/蒙蒙 一劳曹、第九天 我趴在偏房一處隱蔽的房頂上張望奴愉。 院中可真熱鬧,春花似錦铁孵、人聲如沸锭硼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,199評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽檀头。三九已至,卻和暖如春岖沛,著一層夾襖步出監(jiān)牢的瞬間暑始,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,418評論 1 260
  • 我被黑心中介騙來泰國打工廊镜, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留唉俗,地道東北人配椭。 一個月前我還...
    沈念sama閱讀 45,401評論 2 352
  • 正文 我出身青樓颂郎,卻偏偏與公主長得像容为,于是被迫代替她去往敵國和親坎背。 傳聞我的和親對象是個殘疾皇子寄雀,可洞房花燭夜當晚...
    茶點故事閱讀 42,700評論 2 345

推薦閱讀更多精彩內(nèi)容