自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

360移動(dòng)端性能監(jiān)控實(shí)踐QDAS-APM(iOS篇)

開(kāi)發(fā) 開(kāi)發(fā)工具
360作為一家注重用戶(hù)體驗(yàn)的公司,app的性能問(wèn)題無(wú)疑是被重點(diǎn)關(guān)注的,我們也總結(jié)出了一套自己的app性能監(jiān)控體系。本文介紹360在iOS端移動(dòng)端線(xiàn)上性能監(jiān)控方案——QDAS-APM。

一、背景

app的性能問(wèn)題是影響用戶(hù)體驗(yàn)的重要因素之一。性能問(wèn)題主要包含:崩潰、網(wǎng)絡(luò)請(qǐng)求錯(cuò)誤或者超時(shí)、UI響應(yīng)速度慢、主線(xiàn)程卡頓、CPU和內(nèi)存使用高、耗電量大等等。大多問(wèn)題的原因在于開(kāi)發(fā)者錯(cuò)誤地使用了線(xiàn)程、鎖、系統(tǒng)函數(shù)、編程規(guī)范問(wèn)題、數(shù)據(jù)結(jié)構(gòu)等等。解決這個(gè)問(wèn)題的關(guān)鍵在于盡早發(fā)現(xiàn)和定位問(wèn)題。

360作為一家注重用戶(hù)體驗(yàn)的公司,app的性能問(wèn)題無(wú)疑是被重點(diǎn)關(guān)注的,我們也總結(jié)出了一套自己的app性能監(jiān)控體系。在平時(shí)開(kāi)發(fā)和用戶(hù)反饋的問(wèn)題中,我們對(duì)性能問(wèn)題進(jìn)行了歸納,總結(jié)出了5個(gè)分別是:資源文件如何掌控、 版本質(zhì)量如何保證、線(xiàn)上問(wèn)題如何排查、開(kāi)發(fā)階段如何防止性能衰減、性能監(jiān)控是否能真實(shí)反映用戶(hù)體驗(yàn)。同時(shí)學(xué)習(xí)了業(yè)內(nèi)相對(duì)完善的性能監(jiān)控平臺(tái)上的功能原理。從而得出了360在iOS端移動(dòng)端線(xiàn)上性能監(jiān)控方案——QDAS-APM。

二、功能和原理

QDAS-APM已經(jīng)實(shí)現(xiàn)以下功能監(jiān)控:

  • 頁(yè)面渲染時(shí)長(zhǎng)
  • 主線(xiàn)程卡頓
  • 網(wǎng)絡(luò)錯(cuò)誤
  • FPS
  • 大文件存儲(chǔ)
  • CPU
  • 內(nèi)存使用
  • Crash
  • 啟動(dòng)時(shí)長(zhǎng)

下面按照功能詳細(xì)介紹實(shí)現(xiàn)細(xì)節(jié)和原理。另外用戶(hù)在使用app時(shí)會(huì)感知性能問(wèn)題,我們可以將其轉(zhuǎn)化為具體的性能監(jiān)控指標(biāo)。

1. 頁(yè)面渲染時(shí)長(zhǎng)

什么是頁(yè)面渲染時(shí)長(zhǎng)?頁(yè)面渲染時(shí)長(zhǎng)其實(shí)是從頁(yè)面初始化到用戶(hù)能看到頁(yè)面效果的時(shí)間長(zhǎng)度。所要了解的指標(biāo)有:

  • 生命周期系統(tǒng)方法執(zhí)行時(shí)長(zhǎng)
  • 頁(yè)面類(lèi)名
  • 啟動(dòng)類(lèi)型
  • 執(zhí)行耗時(shí)
  • 插件名稱(chēng)

關(guān)鍵度量的指標(biāo)是執(zhí)行耗時(shí),不同的方法和步驟產(chǎn)生的耗時(shí)在用戶(hù)能接受的范圍內(nèi)才被認(rèn)為是合理。其他指標(biāo)則是起有關(guān)聯(lián)性作用和定位問(wèn)題。直接hook UIViewController的方法明顯是不可行的,原因是它只作用在UIViewController的方法,而app中大部分都采用繼承UIViewController的方式。

這里列出兩個(gè)可行性方案:

  • 采用KVO,我們知道對(duì)于任意對(duì)象進(jìn)行KVO操作時(shí),系統(tǒng)都會(huì)幫你動(dòng)態(tài)的創(chuàng)建一個(gè)復(fù)制類(lèi),同時(shí)實(shí)現(xiàn)了setter getter函數(shù)的覆蓋和函數(shù)實(shí)現(xiàn)。
  • 采用runtime遍歷所有類(lèi)為UIViewController的子類(lèi),再進(jìn)行動(dòng)態(tài)替換。

這兩種方式更加推薦***種,出于對(duì)兼容性、性能、以及能夠直接獲取UIViewController的子類(lèi)的IMP。那具體如何實(shí)現(xiàn)呢?總結(jié)歸納為三步驟:

  • 需要?jiǎng)?chuàng)建一個(gè)UIViewController的類(lèi)別,對(duì)UIViewController的實(shí)例進(jìn)行KVO,目的是讓KVO創(chuàng)建需要監(jiān)控UIViewController的子類(lèi)。
  • 添加需要監(jiān)控的方法,在KVO創(chuàng)建出來(lái)的子類(lèi)添加需要Swizzle的方法對(duì)應(yīng)的SEL及其IMP。目的是控制調(diào)用原來(lái)類(lèi)的方法時(shí)機(jī)。
  • 在UIViewController的實(shí)例銷(xiāo)毀時(shí),在dealloc方法里將KVO監(jiān)聽(tīng)移除,不然會(huì)導(dǎo)致Crash。

舉個(gè)例子:我們以監(jiān)控到qh_viewDidLoad方法舉例:

  1. static void qh_viewDidLoad(UIViewController *kvo_self, SEL _sel) 
  2.     Class kvo_cls = object_getClass(kvo_self); 
  3.     Class origin_cls = class_getSuperclass(kvo_cls); 
  4.  
  5.     // 注意點(diǎn) 
  6.     IMP origin_imp = method_getImplementation(class_getInstanceMethod(origin_cls, _sel)); 
  7.  
  8.     void(*func)(UIViewController *, SEL) =  (void(*)(UIViewController *, SEL))origin_imp; 
  9.  
  10.         CFAbsoluteTime startTime = CACurrentMediaTime(); 
  11.         func(kvo_self, _sel); 
  12.         CFAbsoluteTime endTime = CACurrentMediaTime(); 
  13.         NSTimeInterval duration = (endTime - startTime)*1000; 
  14.  
  15.     NSLog(@"Class %@ cost %g in viewDidLoad", [kvo_self class], duration); 

會(huì)有一種特殊情況,如果KVO生成的類(lèi)中對(duì)應(yīng)的類(lèi)原本沒(méi)有實(shí)現(xiàn)監(jiān)控方法,那么會(huì)造成什么后果呢?KVO內(nèi)部生成的NSKVONotifying_ViewController實(shí)際上時(shí)繼承自ViewController,因此直接取出對(duì)應(yīng)的IMP調(diào)用。

OK,上面說(shuō)的是對(duì)UIViewController類(lèi)方法的執(zhí)行時(shí)長(zhǎng)統(tǒng)計(jì)。我們還想知道用戶(hù)真正頁(yè)面跳轉(zhuǎn)后看到***針頁(yè)面圖像的時(shí)長(zhǎng)要如何采集呢?

那是不是將UIViewController類(lèi)的init+loadView+viewDidLoad+viewWillAppear+viewDidAppear方法執(zhí)行時(shí)長(zhǎng)之和就是頁(yè)面渲染時(shí)長(zhǎng)了呢?

答案是否定的,下面舉了三個(gè)反面例子:

如何才能判斷屏幕渲染完成?是否能間接獲取屏幕渲染時(shí)長(zhǎng)?

對(duì)于異步回調(diào)和異步渲染這兩種方式,用上面提到的5個(gè)方法執(zhí)行時(shí)長(zhǎng)之和是不適用的。接下來(lái)看下如何相對(duì)準(zhǔn)確地來(lái)統(tǒng)計(jì)和計(jì)算的方案。

頁(yè)面渲染的時(shí)長(zhǎng)和頁(yè)面的布局時(shí)長(zhǎng)會(huì)在未來(lái)的某個(gè)時(shí)間點(diǎn)上達(dá)到一致。要想得到頁(yè)面渲染的時(shí)長(zhǎng)可以間接地參考頁(yè)面的布局完成時(shí)長(zhǎng)。在UIViewController的生命周期方法里有一個(gè)方法叫viewDidLayoutSubviews,它是干什么的呢?它其實(shí)是告訴了控制器的subviews布局完成的時(shí)間點(diǎn)。一般情況下會(huì)被調(diào)用兩次,在不同的操作系統(tǒng)版本里調(diào)用次數(shù)也不同。

2. 主線(xiàn)程卡頓分析

主線(xiàn)程的卡頓直接影響用戶(hù)使用體驗(yàn),其表現(xiàn)在頁(yè)面的操作流暢性影響。首先引入一個(gè)概念FPS(Frames Per Second):每秒顯示連續(xù)圖片的幀數(shù)。每秒幀數(shù)越多,UI操作就越流暢。一般應(yīng)用保持在每秒50~60幀數(shù),會(huì)給用戶(hù)帶來(lái)流暢的感覺(jué),反之,用戶(hù)則會(huì)感知到卡頓。那為什么會(huì)出現(xiàn)主線(xiàn)程卡頓呢?首先了解下,每一幀圖像顯示到屏幕的原理。

這是觸屏幕顯示的原理流程圖。CPU負(fù)責(zé)計(jì)算顯示內(nèi)容,包括視圖的創(chuàng)建、布局計(jì)算、圖片解碼、文本繪制等,cpu會(huì)把計(jì)算后的結(jié)果提交給GPU,GPU進(jìn)行變換、合成、渲染后,將渲染結(jié)果提交到幀緩沖區(qū),當(dāng)下一次垂直同步信號(hào)到來(lái)時(shí),視頻控制器從緩沖區(qū)里獲取視圖顯示到屏幕上。明白了就屏幕顯示的原理,接下來(lái)看下為甚么會(huì)產(chǎn)生卡頓。

圖上提到 V-Sync 是什么,以及為什么要在 iPhone 的顯示流程引入它呢?在 iPhone 中使用的是雙緩沖機(jī)制,即上圖中的 FrameBuffer 有兩個(gè)緩沖區(qū),雙緩沖區(qū)的引入是為了提升顯示效率,但是與此同時(shí),他引入了一個(gè)新的問(wèn)題,當(dāng)視頻控制器還未讀取完成時(shí),比如屏幕內(nèi)容剛顯示一半時(shí),GPU 將新的一幀內(nèi)容提交到幀緩沖區(qū)并把兩個(gè)緩沖區(qū)進(jìn)行交換后,視頻控制器就會(huì)把新的一幀數(shù)據(jù)的下半段顯示到屏幕上,造成畫(huà)面撕裂現(xiàn)象,V-Sync 就是為了解決畫(huà)面撕裂問(wèn)題,開(kāi)啟 V-Sync 后,GPU 會(huì)在顯示器發(fā)出 V-Sync 信號(hào)后,去進(jìn)行新幀的渲染和緩沖區(qū)的更新。

搞清楚了 iPhone 的屏幕顯示原理后,下面來(lái)看看在 iPhone 上為什么會(huì)出現(xiàn)卡頓現(xiàn)象,上文已經(jīng)提及在圖像真正在屏幕顯示之前,CPU 和 GPU 需要完成自身的任務(wù),而如果他們完成的時(shí)間錯(cuò)過(guò)了下一次 V-Sync 的到來(lái)(通常是1000/60=16.67ms),這樣就會(huì)出現(xiàn)顯示屏還是之前幀的內(nèi)容,這就是界面卡頓的原因。不難發(fā)現(xiàn),無(wú)論是 CPU 還是 GPU 引起錯(cuò)過(guò) V-Sync 信號(hào),都會(huì)造成界面卡頓。

3. 網(wǎng)絡(luò)監(jiān)控

網(wǎng)絡(luò)監(jiān)控一般通過(guò) NSURLProtocol 和代碼注入(Hook)這兩種方式來(lái)實(shí)現(xiàn),由于 NSURLProtocol 作為上層接口,使用起來(lái)更為方便,NSURLProtocol 屬于 URL Loading System 體系中,應(yīng)用層的協(xié)議支持有限,只支持 FTP,HTTP,HTTPS 等幾個(gè)應(yīng)用層協(xié)議,對(duì)于使用其他協(xié)議的流量則束手無(wú)策,所以存在一定的局限性。監(jiān)控底層網(wǎng)絡(luò)庫(kù) CFNetwork 則沒(méi)有這個(gè)限制。如果本地有https的證書(shū)驗(yàn)證也不適用于NSURLProtocol這種方式。容易引起業(yè)務(wù)數(shù)據(jù)丟失問(wèn)題。

(1) NSURLProtocol

上圖是基于NSURLProtocol協(xié)議來(lái)實(shí)現(xiàn)的,通過(guò)繼承自NSURLProtocol,并注冊(cè)。通過(guò)代理和自身方法來(lái)得到網(wǎng)絡(luò)請(qǐng)求相關(guān)的指標(biāo)。

(2) HOOK方式—NSProxy

NSProxy is an abstract superclass defining an API for objects

that act as stand-ins for other objects or for objects that don’t exist yet.

Typically, a message to a proxy is forwarded to the real object or causes the proxy to load (or

transform itself into) the real object. Subclasses of NSProxy can be used to implement transparent

distributed messaging (for example, NSDistantObject) or for lazy instantiation of objects that are expensive to create.

上面的這段英文是 Apple 官方文檔給 NSProxy 的定義,NSProxy 和 NSObject 一樣都是根類(lèi),它是一個(gè)抽象類(lèi),可以通過(guò)繼承它,并重寫(xiě) -forwardInvocation: 和 -methodSignatureForSelector: 方法以實(shí)現(xiàn)消息轉(zhuǎn)發(fā)到另一個(gè)實(shí)例。綜上,NSProxy 的目的就是負(fù)責(zé)將消息轉(zhuǎn)發(fā)到真正的 target 的代理類(lèi)。

那為什么我們不用Method swizzling 替換方法需要指定類(lèi)名?是因?yàn)?NSURLConnectionDelegate 和 NSURLSessionDelegate 是由業(yè)務(wù)方指定,通常來(lái)說(shuō)是不確定,所以這種場(chǎng)景不適合使用 Method swizzling。使用 NSProxy 可以解決,具體實(shí)現(xiàn):proxy delegate 替換 NSURLConnection 和 NSURLSession 原來(lái)的 delegate,當(dāng) proxy delegate 收到回調(diào)時(shí),如果是要 hook 的方法,則調(diào)用 proxy 的實(shí)現(xiàn),proxy 的實(shí)現(xiàn)***會(huì)調(diào)用原來(lái)的 delegate;反之,則通過(guò)消息轉(zhuǎn)發(fā)機(jī)制將消息轉(zhuǎn)發(fā)給原來(lái)的 delegate。

下圖示意了整個(gè)操作流程:

通過(guò)對(duì)NSURLConnection、NSURLSession和CFNetwork這三個(gè)類(lèi)中關(guān)鍵方法的hook來(lái)獲取上報(bào)指標(biāo)。具體hook哪些方法,請(qǐng)看下圖:

將hook方法中得到的相關(guān)指標(biāo)整理成需要的格式上報(bào)到服務(wù)端,服務(wù)端通過(guò)數(shù)據(jù)處理和拆分指標(biāo),匯總加計(jì)算生成最終的報(bào)表。

三、QDAS-APM在集成和使用上的便捷

由于sdk功能基本上采用的都是主動(dòng)采集功能,無(wú)需二次開(kāi)發(fā),也無(wú)需額外引入系統(tǒng)庫(kù)。所以在集成和使用上非常便捷。在sdk的集成上,只需要三步驟:

  • 引入sdk庫(kù)
  • 引入sdk頭文件
  • 在app的didFinishLauchingWithOptions里初始化sdk,并傳入appkey即可。

【本文是51CTO專(zhuān)欄機(jī)構(gòu)360技術(shù)的原創(chuàng)文章,微信公眾號(hào)“360技術(shù)( id: qihoo_tech)”】

戳這里,看該作者更多好文

責(zé)任編輯:趙寧寧 來(lái)源: 51CTO專(zhuān)欄
相關(guān)推薦

2014-08-14 11:52:34

ITILAPM

2014-04-24 13:21:20

2018-09-03 09:22:25

監(jiān)控服務(wù)器性能

2014-09-02 11:40:37

APPAPM移動(dòng)應(yīng)用監(jiān)測(cè)

2014-07-07 17:40:34

云智慧

2014-11-06 10:00:46

Gartner

2020-03-20 08:30:56

手機(jī)移動(dòng)端適配

2015-07-27 11:00:33

應(yīng)用性能監(jiān)控工具APM

2021-09-03 09:44:13

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

2010-05-26 18:40:54

Linux性能監(jiān)控

2023-07-24 09:03:38

汽車(chē)之家頁(yè)面性能監(jiān)控

2010-05-26 18:21:04

Linux性能監(jiān)控

2010-05-26 18:31:51

Linux性能監(jiān)控

2011-11-08 21:47:37

Linux 監(jiān)控 IO

2014-05-26 16:52:29

移動(dòng)前端web組件

2017-03-02 12:39:04

移動(dòng)端iOS監(jiān)控體系

2022-12-29 08:56:30

監(jiān)控服務(wù)平臺(tái)

2023-04-21 10:05:00

B端項(xiàng)目頁(yè)面

2019-10-25 10:42:51

框架Web開(kāi)發(fā)

2010-12-24 13:25:44

Linux性能監(jiān)控CPU
點(diǎn)贊
收藏

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