日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

360移动端性能监控实践QDAS-APM(iOS篇)

發(fā)布時間:2023/12/29 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 360移动端性能监控实践QDAS-APM(iOS篇) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

一、背景

360是一家注重用戶體驗的公司,公司的口號是用戶至上。在這么一個注重用戶體驗的氛圍里,app的性能問題無疑是被重點關(guān)注的,同樣也是造成用戶流失的罪魁禍首之一。性能問題主要包含:崩潰、網(wǎng)絡請求錯誤或者超時、UI響應速度慢、主線程卡頓、CPU和內(nèi)存使用高、耗電量大等等。大多問題的原因在于開發(fā)者錯誤地使用了線程、鎖、系統(tǒng)函數(shù)、編程規(guī)范問題、數(shù)據(jù)結(jié)構(gòu)等等。解決這個問題的關(guān)鍵在于盡早發(fā)現(xiàn)和定位問題。

目前國內(nèi)各大公司都有自己的一套app性能監(jiān)控體系,360也不例外。在平時開發(fā)和用戶反饋的問題中,對性能問題進行了歸納總結(jié)出了5個分別是:資源文件如何掌控、 版本質(zhì)量如何保證、線上問題如何排查、開發(fā)階段如何防止性能衰減、性能監(jiān)控是否能真實反映用戶體驗。同時學習了業(yè)內(nèi)相對完善的性能監(jiān)控平臺上的功能原理。從而得出了360在iOS端移動端線上性能監(jiān)控方案——QDAS-APM。

二、功能和原理

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

  • 頁面渲染時長
  • 主線程卡頓
  • 網(wǎng)絡錯誤
  • FPS
  • 大文件存儲
  • CPU
  • 內(nèi)存使用
  • Crash
  • 啟動時長

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

(1)頁面渲染時長

什么是頁面渲染時長,其實是從頁面初始化到用戶能看到頁面效果的時間長度。所要了解的指標有生命周期系統(tǒng)方法執(zhí)行時長、頁面類名、啟動類型、執(zhí)行耗時和插件名稱。關(guān)鍵度量的指標是執(zhí)行耗時,不同的方法和步驟產(chǎn)生的耗時在用戶能接受的范圍內(nèi)才被認為是合理。其他指標則是起有關(guān)聯(lián)性作用和定位問題。直接hook UIViewController的方法明顯是不可行的,原因是它只作用在UIViewController的方法,而app中大部分都采用繼承UIViewController的方式。

這里列出兩個可行性方案:

1、采用KVO,我們知道對于任意對象進行KVO操作時,系統(tǒng)都會幫你動態(tài)的創(chuàng)建一個復制類,同時實現(xiàn)了setter getter函數(shù)的覆蓋和函數(shù)實現(xiàn)。

2、采用runtime遍歷所有類為UIViewController的子類,再進行動態(tài)替換。

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

1、需要創(chuàng)建一個UIViewController的類別,對UIViewController的實例進行KVO,目的是讓KVO創(chuàng)建需要監(jiān)控UIViewController的子類。

2、添加需要監(jiān)控的方法,在KVO創(chuàng)建出來的子類添加需要Swizzle的方法對應的SEL及其IMP。目的是控制調(diào)用原來類的方法時機。

3、在UIViewController的實例銷毀時,在dealloc方法里將KVO監(jiān)聽移除,不然會導致Crash。

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

static void qh_viewDidLoad(UIViewController *kvo_self, SEL _sel) {Class kvo_cls = object_getClass(kvo_self);Class origin_cls = class_getSuperclass(kvo_cls);// 注意點IMP origin_imp = method_getImplementation(class_getInstanceMethod(origin_cls, _sel));void(*func)(UIViewController *, SEL) = (void(*)(UIViewController *, SEL))origin_imp;CFAbsoluteTime startTime = CACurrentMediaTime();func(kvo_self, _sel);CFAbsoluteTime endTime = CACurrentMediaTime();NSTimeInterval duration = (endTime - startTime)*1000;NSLog(@"Class %@ cost %g in viewDidLoad", [kvo_self class], duration); }

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

OK,上面說的是對UIViewController類方法的執(zhí)行時長統(tǒng)計。我們還想知道用戶真正頁面跳轉(zhuǎn)后看到第一針頁面圖像的時長要如何采集呢?那是不是將UIViewController類的init+loadView+viewDidLoad+viewWillAppear+viewDidAppear方法執(zhí)行時長之和就是頁面渲染時長了呢?答案是否定的,下面舉了三個反面例子:

對于異步回調(diào)和異步渲染這兩種方式,用上面提到的5個方法執(zhí)行時長只和是不適用的。接下來看下如何相對準確的來統(tǒng)計和計算的方案。

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

(2)主線程卡頓分析

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

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

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

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

主線程卡頓監(jiān)控的實現(xiàn)思路:開辟一個子線程,然后實時計算 kCFRunLoopBeforeSources 和 kCFRunLoopAfterWaiting 兩個狀態(tài)區(qū)域之間的耗時是否超過某個閥值,來斷定主線程的卡頓情況,然后通過采集當前主線程的堆棧信息和相關(guān)指標。從而上報到服務端進行處理,最終生成報表。FPS 的刷新頻率非常快,容易發(fā)生抖動,直接通過比較 FPS 來偵測卡頓是比較困難的。主線程卡頓監(jiān)控也會發(fā)生抖動,所以提出綜合方案,結(jié)合主線程監(jiān)控、FPS 監(jiān)控,以及 CPU 使用率等指標,作為判斷卡頓的標準。

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

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

NSURLProtocol


上圖是基于NSURLProtocol協(xié)議來實現(xiàn)的,通過繼承自NSURLProtocol,并注冊。通過代理和自身方法來得到網(wǎng)絡請求相關(guān)的指標。

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 一樣都是根類,它是一個抽象類,可以通過繼承它,并重寫 -forwardInvocation: 和 -methodSignatureForSelector: 方法以實現(xiàn)消息轉(zhuǎn)發(fā)到另一個實例。綜上,NSProxy 的目的就是負責將消息轉(zhuǎn)發(fā)到真正的 target 的代理類。

那為什么我們不用Method swizzling 替換方法需要指定類名?是因為 NSURLConnectionDelegate 和 NSURLSessionDelegate 是由業(yè)務方指定,通常來說是不確定,所以這種場景不適合使用 Method swizzling。使用 NSProxy 可以解決,具體實現(xiàn):proxy delegate 替換 NSURLConnection 和 NSURLSession 原來的 delegate,當 proxy delegate 收到回調(diào)時,如果是要 hook 的方法,則調(diào)用 proxy 的實現(xiàn),proxy 的實現(xiàn)最后會調(diào)用原來的 delegate;反之,則通過消息轉(zhuǎn)發(fā)機制將消息轉(zhuǎn)發(fā)給原來的 delegate。下圖示意了整個操作流程。


通過對NSURLConnection、NSURLSession和CFNetwork這三個類中關(guān)鍵方法的hook來獲取上報指標。具體hook哪些方法,請看下圖。

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

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

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

1、引入sdk庫

2、引入sdk頭文件

3、在app的didFinishLauchingWithOptions里初始化sdk,并傳入appkey即可。







參考:

美團Herz


iOS性能監(jiān)控方案

(360技術(shù)原創(chuàng)內(nèi)容,轉(zhuǎn)載請務必保留文末二維碼,謝謝~)

關(guān)于360技術(shù) 360技術(shù)是360技術(shù)團隊打造的技術(shù)分享公眾號,每天推送技術(shù)干貨內(nèi)容
更多技術(shù)信息歡迎關(guān)注“360技術(shù)”微信公眾號

總結(jié)

以上是生活随笔為你收集整理的360移动端性能监控实践QDAS-APM(iOS篇)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。