老司機(jī)高德納曾經(jīng)說過:程序開發(fā)人員為提升程序效率在錯誤的方向和時間點(diǎn)浪費(fèi)了太多的時間,過早優(yōu)化是編程領(lǐng)域的萬惡之源
1.內(nèi)存優(yōu)化
一個應(yīng)用中內(nèi)存消耗分成兩個部分:一個是??臻g一個是堆空間。
??臻g:每一個線程都會對應(yīng)一個專用的棧空間,??臻g可以在線程存在期間使用,但是有最大棧空間限制。如果超出這個限制,將會導(dǎo)致棧移除,程序被殺死。
以下幾種情況,都是由于棧空間溢出,導(dǎo)致程序被殺死:
- 可以被遞歸調(diào)用的最大方法數(shù)目。因?yàn)槊恳粋€方法都會對應(yīng)一個棧幀,棧幀會消耗一定字節(jié)的內(nèi)存。(這就是為什么,循環(huán)調(diào)用一定會崩潰,因?yàn)楹瘮?shù)棧幀消耗的字節(jié)數(shù)太多,導(dǎo)致內(nèi)存溢出)
- 方法中定義的變量個數(shù)太多。當(dāng)然這只是一個理論上可能會導(dǎo)致棧溢出的情況,實(shí)際開發(fā)中基本不會因?yàn)槎x過多變量被系統(tǒng)kill掉
- 視圖的層級太深。遞歸的調(diào)用layoutSubviews方法跟drawRect方法。
堆空間:每一個進(jìn)城的所有線程都是會對應(yīng)同一個堆空間。堆空間是系統(tǒng)分配的。通過類創(chuàng)建的對象相關(guān)的所有數(shù)據(jù)都是放在堆中的。所以重量級model在系統(tǒng)收到didReceiveMemoryWarning的時候進(jìn)行清空,然后在必要的時候重新賦值對于系統(tǒng)優(yōu)化是非常必要的。
內(nèi)存管理的原則
- 你可以擁有你自己創(chuàng)建的對象,比如 new,alloc,copy,mutablecopy
- 你可以使用MRC中的retain 或者是ARC中的_Strong來標(biāo)示對一個對象的強(qiáng)引用
- 在MRC中當(dāng)不需要一個對象的時候,需要使用release方法來釋放對象的持有關(guān)系,ARC中不需要做任何操作
避免循環(huán)引用引發(fā)的內(nèi)存泄漏
1.delegate weak修飾
2.__weak 修飾被block捕獲的局部變量
3.NSTimer,對象持有定時器,定時器也持有對象。解決方法1.自定義清理時機(jī),可以退出控制器時,也可以點(diǎn)擊某一個按鈕時。
2.能耗
基本沒什么好說的,無關(guān)緊要
3.多線程
記?。褐骶€程用來更新UI,自線程用來做讀寫文件等比較耗時的操作
每個線程大概會消耗1KB的內(nèi)核內(nèi)存空間。主線程會占用1MB的棧空間,子線程會占用512KB的棧空間。
多線程的弊端:
- 上下文切換,耗費(fèi)時間
- 創(chuàng)建耗費(fèi)時間,一般一條線程創(chuàng)建之后啟動大概耗費(fèi)29毫秒
三種多線程的比較
1.GCD - 抽象程度高
- 兩種隊(duì)列開箱即用:main和global
- 可以創(chuàng)建更多的隊(duì)列
- 硬性要求少于64個線程
2.NSOperationQueue
- 無默認(rèn)隊(duì)列
- 應(yīng)用管理自己創(chuàng)建的隊(duì)列
- 隊(duì)列是優(yōu)先級的隊(duì)列
- 操作可以有不同的優(yōu)先級
- 使用cancel可以取消操作
- 可以等待某個操作執(zhí)行完成
屬性默認(rèn)實(shí)用的是atomic,但是這樣做屬性也不一定是線程安全的。如果需要做線程安全操作,更好的是用鎖。所以不要將屬性設(shè)置為atomic。
注意:@synchronized指令會拖慢應(yīng)用的運(yùn)行速度,因?yàn)樵谌魏螘r間內(nèi)都只有一個線程在臨界區(qū)。
以下是三種比較常用的鎖
1.NSLock
這是一種低級別的鎖,一旦獲得了鎖,那么將會執(zhí)行臨界區(qū)中的內(nèi)容,并且不會超過一個線程執(zhí)行。釋放鎖則標(biāo)志著臨界區(qū)結(jié)束。有個注意點(diǎn)就是 釋放鎖的操作一定要跟加鎖操作在同一線程。
2.NSRecursiveLock
在調(diào)用lock之前,NSLock必須先調(diào)用unlock。但是正如名字暗示的那樣,NSRecursiveLock允許在被解鎖之前鎖定多次。只要解鎖的次數(shù)跟鎖定的次數(shù)相匹配,那么鎖就可以釋放。

上圖是各種鎖的性能。附上老司機(jī)的關(guān)于iOS中鎖問題研究文章鏈接:https://bestswifter.com/ios-lock/
4.應(yīng)用的首次啟動時間
應(yīng)用首次啟動往往會做很多事情,包括
1.加載默認(rèn)項(xiàng)
2.檢查測試版本
3.初始化應(yīng)用標(biāo)識符
4.初始化崩潰報(bào)告
5.建立分析方法
6.建立UI基礎(chǔ)框架
7.建立內(nèi)存緩存
附上 今日頭條開機(jī)啟動優(yōu)化的文章:http://www.cocoachina.com/ios/20170208/18651.html
5.UI層面的優(yōu)化
記住下面幾個原則
- 盡量減少主線程中的工作
- 避免視圖層級中的多層嵌套
- 盡可能的延遲視圖的加載,也就是常說的懶加載。并且對于可以重用的視圖,進(jìn)行復(fù)用 https://github.com/facebookarchive/AsyncDisplayKit
- UIImageView 注意分場景下使用imageNamed跟imageWithContentsofFile。使用圖片與imageView大家接近,避免imageview對圖片縮放操作。
- UITableView的優(yōu)化:http://www.itdecent.cn/p/4780b10dae55
- 慎用自動布局。自動布局在視圖比較多的時候非常耗費(fèi)CPU性能。如果頁面元素太多,建議使用原生的frame布局,對于提升幀率有非常大的幫助。當(dāng)然了marsory對于計(jì)算布局有非常大的幫助,往往很復(fù)雜的約束,frame要寫一大堆代碼,但是marsory就可以寫幾行就可以了。根據(jù)業(yè)務(wù)不同,可以自己做選擇。