成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

iOS性能優(yōu)化系列

移動(dòng)開發(fā) iOS
說起來慚愧,我真的很少遇到性能問題。以前假設(shè)中的性能問題,很多是根本不存在的。事前計(jì)劃也杜絕了不了性能問題的產(chǎn)生,所以不如暫時(shí)忘記它吧。當(dāng)然對于一些常識性的提高性能的設(shè)計(jì),仍然是必須的。

這一系列文章是我的讀書筆記,整理一下,也算是溫故而知新。

性能問題的處理流程

  • 發(fā)現(xiàn)/重現(xiàn)問題
  • 利用工具剖析
  • 形成假設(shè)
  • 改進(jìn)代碼和設(shè)計(jì)

在以上的四個(gè)步驟中循環(huán)反復(fù),直到問題解決。

Profile!不要猜!

性能優(yōu)化的主要策略:

  • 不要做無用功:不要在啟動(dòng)時(shí)花幾百ms來做logging,不要為同樣的數(shù)據(jù)做多次查詢
  • 試圖重用:對于創(chuàng)建過程昂貴的對象,要重用而不是重新創(chuàng)建
    • Table View的cell
    • Date/Number的formatter
    • 正則表達(dá)式
    • SQLite語句
  • 使用更快的方式設(shè)計(jì)、編程:選擇正確的集合對象和算法來進(jìn)行編程、選擇適合的數(shù)據(jù)存儲格式(plist、SQLite)、優(yōu)化SQLite查詢語句
  • 事先做優(yōu)化
    • 對于昂貴的計(jì)算,要進(jìn)行事先計(jì)算。iCal中的重復(fù)事件,是預(yù)先計(jì)算出來的,并保存到數(shù)據(jù)庫中。
    • 事先計(jì)算并緩存一些對象,可能會占用大量的內(nèi)存。注意不要將這些對象聲明為static并常駐內(nèi)存。
  • 事后做優(yōu)化:異步加載、懶加載
  • 為伸縮性而做優(yōu)化:當(dāng)數(shù)據(jù)有10條、100條、1000條甚至更多的時(shí)候,應(yīng)用程序的性能不應(yīng)該對應(yīng)的呈數(shù)量級式的增長,否則無法使用。

說起來慚愧,我真的很少遇到性能問題。以前假設(shè)中的性能問題,很多是根本不存在的。事前計(jì)劃也杜絕了不了性能問題的產(chǎn)生,所以不如暫時(shí)忘記它吧。當(dāng)然對于一些常識性的提高性能的設(shè)計(jì),仍然是必須的。

二:iOS應(yīng)用啟動(dòng)速度優(yōu)化

很多app的開發(fā)者都不重視app的啟動(dòng)速度,這對于碎片化使用情景的用戶來說,簡直是災(zāi)難。

iOS應(yīng)用的啟動(dòng)速度

應(yīng)用啟動(dòng)時(shí),會播放一個(gè)放大的動(dòng)畫。iPhone上是400ms,iPad上是500ms。最理想的啟動(dòng)速度是,在播放完動(dòng)畫后,用戶就可以使用。

如果應(yīng)用啟動(dòng)過慢,用戶就會放棄使用,甚至永遠(yuǎn)都不再回來。拋開代碼不談,如果抱著PC端游和單機(jī)游戲的思維,在游戲啟動(dòng)時(shí)強(qiáng)加公司Logo,啟動(dòng)動(dòng)畫,并且用戶不可跳過,也會使用戶的成功使用率大大降低。

iOS系統(tǒng)的“看門狗"

為了防止一個(gè)應(yīng)用占用過多的系統(tǒng)資源,開發(fā)iOS的蘋果工程師門設(shè)計(jì)了一個(gè)“看門狗”的機(jī)制。在不同的場景下,“看門狗”會監(jiān)測應(yīng)用的性能。如果超出了該場景所規(guī)定的運(yùn)行時(shí)間,“看門狗”就會強(qiáng)制終結(jié)這個(gè)應(yīng)用的進(jìn)程。開發(fā)者們在crashlog里面,會看到諸如0x8badf00d這樣的錯(cuò)誤代碼(“看門狗”吃了壞的食物,它很不高興)。

場景 “看門狗”超時(shí)時(shí)間
啟動(dòng) 20秒
恢復(fù)運(yùn)行 10秒
懸掛進(jìn)程 10秒
退出應(yīng)用 6秒
后臺運(yùn)行 10分鐘

值得注意的是,Xcode在Debug的時(shí)候,會禁止“看門狗”。

如何測試啟動(dòng)時(shí)間

兩種方法:一種使用NSLog,另外一種使用Time Profiler。

  • 使用NSLog
  •  
    1. 1 CFAbsoluteTime StartTime;  
    2. int main(int argc, char **argv) {  
    3. 3      StartTime = CFAbsoluteTimeGetCurrent(); 
    4.  4      // ...  5 }  6   
    5. 7 - (void)applicationDidFinishLaunching:(UIApplication *)app {  
    6. 8      dispatch_async(dispatch_get_main_queue(), ^{  
    7. 9         
    8. NSLog(@"Launched in %f sec", CFAbsoluteTimeGetCurrent() - StartTime); 
    9. 10      
    10. }); 11      // ... 12  }  
  • 使用Time Profiler
    • Instruments->Time Profiler
    • Profile你的app
    • 切換到CPU strategy view,找到你的app啟動(dòng)的第一幀
    • 搜索-[UIApplication _reportAppLaunchFinished]
    • 找到包含-[UIApplication _reportAppLaunchFinished]的最后一幀,即可計(jì)算出啟動(dòng)時(shí)間

iOS App啟動(dòng)過程

  • 鏈接并加載Framework和static lib
  • UIKit初始化
  • 應(yīng)用程序callback
  • 第一個(gè)Core Animation transaction

鏈接并加載Framework及static lib時(shí)需要注意:

  • 每個(gè)Framework都會增加啟動(dòng)時(shí)間和占用的內(nèi)存
  • 不必要的Framework,不要鏈接
  • 必要的Framework,不要票房為Optional
  • 只在使用在Deployment Target之后發(fā)布的Framework時(shí),才使用Optional(比如你的Deployment Target是iOS 3.0,需要鏈接StoreKit的時(shí)候)
  • 避免創(chuàng)建全局的C++對象

初始化UIKit時(shí)需要注意:

  • 字體、狀態(tài)欄、user defaults、main nib會被初始化
  • 保持main nib盡可能的小
  • User defaults本質(zhì)上是一個(gè)plist文件,保存的數(shù)據(jù)是同時(shí)被反序列化的,不要在user defaults里面保存圖片等大數(shù)據(jù)

應(yīng)用程序的回調(diào):

  • application:willFinishLaunchingWithOptions:
  • 恢復(fù)應(yīng)用程序的狀態(tài)
  • application:didFinishLaunchingWithOptions:

我一直認(rèn)為設(shè)計(jì)的本質(zhì)是折衷。當(dāng)你為了100ms的啟動(dòng)速度優(yōu)化歡欣不已,而無視那長達(dá)10秒的啟動(dòng)動(dòng)畫時(shí),應(yīng)該想想究竟什么是應(yīng)該做的。做正確的事情比把事情做好更重要。

三:事件處理-拯救主線程

用戶經(jīng)常評論app的一個(gè)用詞是“卡頓”,很大的因素是因?yàn)橹骶€程被占用了。用戶的事件是在主線程被處理的,包括點(diǎn)擊、滾動(dòng)、加速計(jì)、Proximity Sensor。

為了保證事件的平滑處理,需要進(jìn)行如下優(yōu)化:

  • 最小化主線程的CPU占用
  • 將工作“搬離”主線程
  • 不要阻塞主線程

最小化主線程的CPU占用

前面兩篇文章,我們接觸到了Time Profiler。使用它可以剖析不同線程的CPU使用情況,并給出調(diào)用堆棧的CPU時(shí)間占用百分比。如果app“卡頓”,并且在Time Profiler的結(jié)果可以找到明確的高占用堆棧,你需要把它優(yōu)化掉。

將工作“搬離”主線程 - 隱式并發(fā)

為了得到更流暢的交互體驗(yàn),iOS已經(jīng)幫我們做了很多事情,Android就沒有這么好運(yùn)了。iOS將以下這些事情搬離了主線程:

  • View和layer的動(dòng)畫(動(dòng)畫繪制前的計(jì)算,而不是drawing過程)
  • Layer的組合計(jì)算(drawing后的疊加)
  • PNG的解碼(是的,你沒看錯(cuò);而且利用了CPU的多核心)

注意滾動(dòng)(Scrolling)不是一個(gè)動(dòng)畫,而是在Main Run Loop中不斷接收事件并且處理。

將工作“搬離”主線程 - 顯式并發(fā)

這里是需要開發(fā)者們搞定的部分。磁盤、網(wǎng)絡(luò)等I/O會阻塞線程,不要把它們放到主線程里。常用的技術(shù)有:

  • Grand Central Dispatch(GCD)
  • NSOperationQueue
  • NSThread

iOS 4.0后,易用的GCD技術(shù)被廣泛使用。例如:

 

  1. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), 
  2. ^{    
  3.  // do something in background     dispatch_async(dispatch_get_main_queue(), ^{        
  4.  // do something on main thread    
  5.  }); }); 

GCD的陷阱

GCD其實(shí)就是線程,只不過提供了一個(gè)更高層次的抽象。過多的線程一定會帶來性能損失,因此GCD設(shè)計(jì)了一個(gè)最高允許的線程值(對開發(fā)者透明,不用管到底有多少)。那么如何解決這個(gè)問題呢?

  • 將隊(duì)列串行化
  • 使用Dispatch sources
  • 使用帶有限制的NSOperationQueue
  • 使用Cocoa Touch提供的異步方法

另外一個(gè)陷阱是線程安全:

  • UIKit必須要在主線程使用,除了UIGraphics,UIBezierPath,UIImage
  • 大多數(shù)CG、CA、Foundation的類,不是線程安全的
  • 如果你使用了ojbc runtime來進(jìn)行introspection,由于它是thread safe的,可能會導(dǎo)致競爭

此外,iOS 4.3添加了DISPATCH_QUEUE_PRIORITY_BACKGROUND,它擁有非常低的優(yōu)先級。這個(gè)優(yōu)先級只用于不太關(guān)心完成時(shí)間的真正的后臺任務(wù),如果要表示較低的優(yōu)先級,你通常需要的是DISPATCH_QUEUE_PRIORITY_LOW

不要阻塞主線程

即使占用了很少的CPU時(shí)間(如果你在Time Profiler中看到這些的數(shù)據(jù)),也可能會阻塞主線程。磁盤、網(wǎng)絡(luò)、Lock、dispatch_sync以及向其它進(jìn)程/線程發(fā)送消息都會阻塞主線 程。Time Profiler只能檢測出占用CPU過多的堆棧,但檢測不了這些IO的問題。

大多數(shù)的阻塞事件,都會伴隨著一個(gè)系統(tǒng)調(diào)用,如:

  • read/write - 讀寫文件
  • send/recv - 收發(fā)網(wǎng)絡(luò)數(shù)據(jù)
  • psynch_mutex_wait - 獲得鎖
  • mach_msg - IPC

System Trace這個(gè)Instrumentor,記錄了所有的系統(tǒng)調(diào)用,以及每次調(diào)用的等待時(shí)間。如果你在System Trace里面發(fā)現(xiàn)了CPU Time很低,但Wait Time很高的調(diào)用,說明在主線程處理I/O已經(jīng)嚴(yán)重?fù)p害了app的性能。

保證主線程的低CPU占用,將I/O移至其它線程,可以大大地提高主線程對交互事件的處理能力。我建議開發(fā)者朋友們寫代碼的時(shí)候,除非是以前遇到過的問題,都沒有必要假設(shè)問題存在。80%的優(yōu)化都是不必要的。

 

責(zé)任編輯:張葉青 來源: 博客
相關(guān)推薦

2019-07-25 13:22:43

AndroidAPK文件優(yōu)化

2021-11-09 09:57:46

Webpack 前端分包優(yōu)化

2022-07-19 16:47:53

Android抖音

2022-03-29 13:27:22

Android優(yōu)化APP

2021-09-03 09:44:13

移動(dòng)端性能優(yōu)化U-APM

2017-01-19 19:07:28

iOS進(jìn)階性能優(yōu)化

2022-04-28 15:07:41

抖音內(nèi)存泄漏Android

2018-05-16 07:41:29

圖片代碼資源

2019-03-21 14:18:38

iOS開發(fā)優(yōu)化原因

2025-06-03 00:00:06

性能優(yōu)化性能指標(biāo)響應(yīng)時(shí)間

2013-12-17 17:05:20

iOS性能優(yōu)化

2014-12-10 10:12:02

Web

2011-08-03 16:51:01

jQuery

2021-11-29 11:13:45

服務(wù)器網(wǎng)絡(luò)性能

2009-09-08 09:45:23

App Engine性

2022-02-16 14:10:51

服務(wù)器性能優(yōu)化Linux

2013-06-09 15:31:35

jQueryjQuery優(yōu)化性能優(yōu)化

2017-08-08 09:45:43

Python性能優(yōu)化

2009-06-16 16:10:59

Hibernate性能

2020-09-19 21:26:56

webpack
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 激情六月丁香婷婷 | 亚洲一区视频在线 | 国产精品国产三级国产aⅴ中文 | 久久人人国产 | 日日碰狠狠躁久久躁96avv | 国产日韩欧美电影 | 成人午夜黄色 | 亚洲一区二区三区免费在线观看 | 成人激情视频在线 | 欧美日韩不卡在线 | 超碰成人免费 | 精品久久香蕉国产线看观看亚洲 | h在线免费观看 | 中文字幕第十页 | 亚洲毛片在线 | 狠狠色狠狠色综合日日92 | 久久久久久国产精品免费免费 | 麻豆一区一区三区四区 | 超碰成人在线观看 | 国产区视频在线观看 | 久久国内精品 | 中国大陆高清aⅴ毛片 | 在线中文字幕第一页 | 精品欧美色视频网站在线观看 | 波多野结衣二区 | 天天干视频 | 久草网址 | 国产在线播 | 亚洲精品一区二区在线 | 中文字幕亚洲精品 | 欧美专区在线 | 成人午夜影院 | 日韩成人一区 | 国产精品久久久久久久久久久久久久 | 欧美视频免费在线 | 亚洲精品中文字幕在线观看 | 午夜在线视频 | 黑人巨大精品欧美黑白配亚洲 | 日韩第一区 | 国产成人精品一区二区三区四区 | 黑人巨大精品欧美一区二区免费 |