本文來自於騰訊bugly開發者社區,非經做者贊成,請勿轉載,原文地址:http://dev.qq.com/topic/578c93ca9644bd524bfcabe8git
「8小時內拼工做,8小時外拼成長」這是你們共同的理想。除了天天忙於工做外,咱們都但願能更多地區吸取領域內的新知識與新技能,從而走向人生巔峯。github
Dev Club 是一個交流移動開發技術,結交朋友,擴展人脈的社羣,成員都是通過審覈的移動開發工程師。每週都會舉行嘉賓分享,話題討論等活動。sql
上一期咱們邀請了騰訊SNG工程師「王少鳴」分享了《React Native項目實戰總結》。數據庫
本期,咱們邀請了騰訊WXG iOS開發工程師「姚海波」爲你們分享《微信讀書iOS性能優化》。
。
如何加入 Dev Club?緩存
移動端開發經驗 >= 2 年,微信掃描下方羣管理微信二維碼,備註姓名-公司(或產品) 申請加入。安全
分享內容簡介:
微信讀書做爲一款閱讀類的新產品,目前還處於快速迭代,不斷嘗試的過程當中,性能問題也在業務的不斷累積中逐漸體現出來。最近的1.3.0版本發佈後,關於性能問題的用戶反饋逐漸增多,爲此,團隊開始作一些針對性的性能問題優化。本次分享主要介紹咱們發現問題、解決問題和預防問題的歷程。性能優化
內容的大致框架:微信
分享人介紹:markdown
姚海波 廣州研發部 iOS開發工程師。網絡
負責過的產品:QQ郵箱iOS客戶端,目前主要負責微信讀書iOS客戶端的開發。
下面是本期分享內容整理
你們晚上好,我是來自廣研的姚海波,你們能夠叫我hypo。目前是微信讀書項目中的iOS開發,主要負責閱讀器相關的模塊,還有APP總體性能優化方面的工做。
今天分享的內容是關於微信讀書iOS開發過程當中,咱們解決性能問題的基本思路和方法,包括發現問題、解決問題和預防問題三個方面。
首先,根據我的的開發經驗,我不得不認可,當應用發展到必定程度後,性能問題就不可能徹底避免。以往咱們老是但願能尋找一種解決性能問題的一勞永逸的方法,實際上是不太現實的。因此咱們換個思路,如何儘早的發現性能問題,而後解決問題。
在發現問題方面,咱們項目也並無什麼高招,主要有兩個方面
用戶反饋(包括測試人員)
受限於測試時間和用戶反饋的積極性,性能問題每每到了比較嚴重的程度,開發人員才真正發現問題。
在線監控
在線監控主要有業務性能監控和卡頓監控
業務性能監控,主要在咱們認爲很是關鍵的操做路徑,例如:
卡頓監控,是用了Bugly的工具,而後經過動態下發開關,用抽樣的方法進行上報
還有一些反饋卡頓的用戶,咱們也會經過這個方法來查找問題
而後,在解決性能問題方法,相信你們都累積了不少經驗。
產生性能問題的緣由多種多樣,因此解決的辦法也不盡相同,各類奇技淫巧都有可能派上用場,這裏我大概介紹一下咱們項目中用到的一些方面:
1. 優化業務流程 2. 合理的線程分配 3. 預處理和延時加載 4. 緩存 5. 使用正確的API
性能優化看似高深,真正落到實處纔會發現,最大的坑每每都隱藏在於業務不斷累積和頻繁變動之處。優化業務流程就是在知足需求的同時,提出更加高效優雅的解決方案,從根本上解決問題。從實踐來看,這種方法解決問題是最完全的,但一般也是難度最大的。
這是咱們其中一個業務優化的案例
看似挺簡單的優化,但真正落到實處,纔會出現其中的坑有多大,因此重構優化的時候,還得有顆堅強的心!
因爲GCD實在太方便了,若是不加控制,大部分須要拋到子線程操做都會被直接加到global隊列,這樣會致使兩個問題:
合理的線程分配,最終目的就是保證主線程儘可能少的處理非UI操做,同時控制整個App的子線程數量在合理的範圍內。
預處理,是將初次顯示須要耗費大量線程時間的操做,提早放到後臺線程進行計算,再將結果數據拿來顯示。
延時加載,是指首先加載當前必須的可視內容,在稍後一段時間內或特定事件時,再觸發其餘內容的加載。這種方式能夠頗有效的提高界面繪製速度,使體驗更加流暢。(UITableView就是最典型的例子)
這兩種方法都是在資源比較緊張的狀況下,優先處理立刻要用到的數據,同時儘量提早加載即將要用到的數據。在微信讀書中閱讀的排版是優先級最高的,所在在閱讀過程當中會預處理下一頁、下一章的排版,同時可能會延時加載閱讀相關的其它數據(如想法、劃線、書籤等)。
cache多是全部性能優化中最經常使用的手段,但也是咱們極不推薦的手段。cache創建的成本低,見效快,可是帶來維護的成本卻很高。若是必定要用,也請謹慎使用,並注意如下幾點:
這方面主要仍是靠經驗的累積
上面只是列舉了幾種常規手段,相信你們在實踐過程當中,確定還有不少的高招。
通過一段時間的性能優化工做,咱們團隊達成了一項共識,與其花那麼時間去發現問題,查問題,還不如多開發一些工具,讓問題儘可能暴露在開發階段,最好達到避免共性問題。因此,咱們老是想開發一些有意思小工具來作這種事情。
下面列舉幾個咱們認識還挺有幫忙的工具:
1.內存泄露檢測工具。 2.FPS/SQL性能監測工具條 3.UI/DataSource主線程檢測工具 4.排版引擎自動化檢測工具 5.書源檢測工具
MLeakFinder,這個已經開源了,是咱們團隊中zeposhe的傑做。
在此以前,內存泄露引發的性能問題是很難被察覺的,只有泄露到了至關嚴重的程度,而後經過Instrument工具,不斷嘗試才得以定位。MLeakFinder能在開發階段,把內存泄露問題暴露無遺,減小了不少潛在的性能問題。
工具條是在DEBUG模式下,以浮窗的形式,實時展現當前可能存在問題的FPS次數和執行時間較長的SQL語句個數,是團隊成員tower開發的。
FPS監測的原理並不複雜,雖然不是百分百準確,但很是實用,由於能夠隨時查看FPS低於某個閾值時的堆棧信息,再結合當時的使用場景,開發人員使用起來很是便利,能夠很快定位到引發卡頓的場景和緣由。SQL語句的監測也很是實用,對於微信讀書,DB的讀寫速度是影響性能的瓶頸之一。所以在DEBUG階段,咱們監測了每一條SQL語句的執行速度,一旦執行時間超出某個閾值,就會表如今工具條的數字上,點擊後能夠進一步查詢到具體的SQL操做以及實際耗時。
頂部工具條點擊後,就能夠查到具體是哪條sql語句慢
這個工具幫助咱們在開發階段發現了不少卡頓問題,尤爲是一些不合理的SQL語句,例如:
在想法圏的優化過程當中,利用這個工具,咱們就發現想法圈第一次加載更多,執行的SQL語句耗時居然達到了1000多毫秒。
_SELECT * FROM WRReview INNER JOIN WRUser ON WRReview.fromId = WRUser.vid WHERE WRReview.type & ? AND WRReview.createTime <= ? ORDER BY WRReview.createTime DESC , WRReview.itemId ASC LIMIT ?_
經過explain,能夠發現這條SQL效率之低:
SEARCH TABLE WRReview SEARCH TABLE WRUser USING INTEGER PRIMARY KEY (rowid=?) USE TEMP B-TREE FOR ORDER BY
優化:給WRReview的 fromId createTime 兩個字段增長了索引,並去掉一個排序字段:
_SELECT * FROM WRReview INNER JOIN WRUser ON WRReview.fromId = WRUser.vid WHERE WRReview.type & ? ORDER BY WRReview.createTime DESC LIMIT ?_
Explain的結果:
SCAN TABLE WRReview USING INDEX WRReview_createTime SEARCH TABLE WRUser USING INTEGER PRIMARY KEY (rowid=?)
該工具是爲了保證全部的UI的操做和DataSource操做必定是在主線程進行。實現原理是經過hook UIView的setNeedsLayout,setNeedsDisplay,setNeedsDisplayInRect三個方法,確保它們都是在主線程執行。子線程操做UI可能會引發什麼問題,蘋果說得並不清楚,實際開發中咱們遇到幾種神奇的問題彷佛都是跟這個有關。
app忽然丟動畫,彷佛iOS系統也有這個bug。雖然沒有確切的證據,但使用這個工具,改完全部的問題後,bug也好了(不止一次是這樣)。
UI操做偶爾響應特別慢,從代碼看沒有任何耗時操做,只是簡單的push某個controller。
莫名的crash,這固然是由於UI操做非線程安全引發的。
更多時候,子線程操做UI也並不必定會發生什麼問題,也正由於不知道會發生什麼,因此更須要咱們警戒,這個工具替咱們掃除了這些隱患。雖然,蘋果表示,如今部分的UI操做也已是線程安全了,但畢竟大部分還不是。DataSource的監測是由於咱們業務定下的原則,保證列表DataSource的線程安全。
排版引擎是微信讀書最核心的功能,排版引擎檢測工具本來是爲了檢驗排版引擎改進過程當中準確性,防止由於業務變動,而影響原來的排版特性。實現原理是結合自動化腳本和App自己的排版引擎,給書庫中的每一本書創建一個鏡像,鏡像的內容包括書籍的每一章每一頁的截圖。而後分析同一頁碼的兩個不一樣版本的圖片差別,就能夠知道不一樣版本的排版引擎渲染效果。可是我發現,只要稍加改進,排版後記錄每一個章節排版耗時,就能夠知道每一個版本變化後同一個章節的耗時變化,以此做爲排版引擎的性能指標。這個工具保證了微信讀書,即便在快速迭代過程當中也不會丟失閱讀的核心體驗。雖然這個工具沒法在其它項目中複用,可是提醒了咱們,能夠經過自動化工具來保證產品最核心功能的體驗。
這個雖然業務相關性比較強,可是對於某些應用的自動化測試也是有效的
微信讀書爲了支持正版版權,目前書源徹底依賴於後臺,不容許本地導入。書源的優劣的直接影響排版的效果和性能。爲了解決了部分書籍沒法打開或者亂碼的問題,咱們藉助了後臺同窗的書源檢測工具。對線上全部epub書籍(大概13,000本)進行掃描,按照章節大小進行排序。對於章節內容特別大的書籍重點檢測,從新排版,解決了一批epub書籍沒法打開的問題。同時針對章節內容亂碼的問題,對全部txt的書籍進行了一次全量掃描,發現了一些問題,但還沒法準確找出全部亂碼的章節,這一點還在努力改善中。
經過上述介紹,咱們能夠看出,性能問題廣泛存在,無可避免,與其花費大量時間,查找線上版本的性能問題,不如提升總體團隊成員性能優化意識,藉助性能查找工具,將性能問題儘早暴露在開發階段,達到預防爲主的效果。
Q1:想問下大家 DB 操做這部分涉及到多線程讀寫是怎麼處理的?
咱們用了FMDB,它已經處理了這種狀況。
Q2:主線程檢測工具備開源嗎?
這個暫時沒有開源,可是會推進開源。
Q3:除了 sqlite 語句的優化以外,db 這部分還有沒有其餘方面的優化工做?
https://github.com/Zepo/GYDataCenter
咱們有一個本身的DB框架,是ORM的,作了不少優化的工做,最近剛開源,你們能夠看看。
Q4:請問大家選擇用sqlite的考量是什麼, 有沒有考慮過使用其餘的db如realm?
選擇sqlite是歷史緣由,由於咱們已經基於sqlite作了一個高性能的DB框架,並且也是通過QQMail App驗證的。realm有考慮過,可是由於不是開源,因此估計不用採用。
Q5:FMDB 的解決方案,我理解是放到一個隊列裏,雖然能夠解決多線程讀寫的問題,可是隊列的處理仍是會阻塞住來自不一樣線程的請求,對麼?
是的。咱們一直也是讀寫都在同一條隊列,其實並無太明顯的性能瓶頸, 由於在sqlite之上咱們還有一層基於model的cache。
Q6:合理的使用線程,多線程之間的同步這塊兒有什麼方案或建議?
這裏咱們也並無什麼通用的方案,原則是儘可能避免使用多線程。必定要用的時候,也是根據業務謹慎選擇。
或者咱們私下能夠再具體討論一些業務場景。
Q7:業務場景裏會不會涉及到有讀操做依賴寫操做完成的狀況,不然會出現讀操做的數據不許確的狀況。FMDB 感受不能很好的解決這個問題。
讀操做 依賴寫操做完成,這種場景必定會有的。可是這種問題應該是業務流程本身控制,而不是DB應該考慮的事情,DB性一能保證的就是按照業務提交的順序,順序執行。
Q8:能不能問下 微信讀書的數據庫的記錄 通常是在什麼級別,百、千?有沒有嘗試去作過一些壓測,數據量達到多少的時候會遇到瓶頸?
微信讀書的數據庫記錄並非很大,單表記錄最多可能也就10w的數據級別。QQ郵箱的mailApp跟咱們是用的同一套,可是數量級別遠大於微信讀書。目前發現的瓶頸是DB文件達到200M以上時,sqlite的性能會明顯受到影響,不過具體緣由還在調查中。有作過一些壓力測試,用來對比CoreData,可是具體數據我這裏暫時沒有。
Q9:卡頓監控這塊能詳細說說麼,用的是Bugly的哪一個工具呢,抽樣上報具體是怎麼樣的?
Bugly庫裏有這個接口能夠用+ (void)enableBlockMonitor:(BOOL)enable
另外再動態下發一個開關,設置這個值就行了。
Q10:微信讀書這麼成功,方便說下她的架構嗎?我以爲架構好纔是她可優化的第一步。
哈哈,如今還遠談不上成功啦。架構要用圖來畫才方便看,我暫時還沒總結整個app的架構, 能夠看看關於閱讀器epub渲染的一個架構。
Q11:sql對於版本升級時表結構發生變化時如何處理?特別是跨版本升級!
https://github.com/Zepo/GYDataCenter 這個是基本ORM的一個框架,會自動把model和sqlite表的字段作一個映射,升級的時候,若是發現sqlite缺乏的字段,會自動建立。可是,由於sqlite不能修改字段,因此咱們也只能用於新增字段。
Q12:大家的 db 是隻有一個文件,仍是嘗試分文件存儲的?
看業務需求,目前是多個DB文件。
更多精彩內容歡迎關注bugly的微信公衆帳號:
騰訊 Bugly是一款專爲移動開發者打造的質量監控工具,幫助開發者快速,便捷的定位線上應用崩潰的狀況以及解決方案。智能合併功能幫助開發同窗把天天上報的數千條 Crash 根據根因合併分類,每日日報會列出影響用戶數最多的崩潰,精準定位功能幫助開發同窗定位到出問題的代碼行,實時上報能夠在發佈後快速的瞭解應用的質量狀況,適配最新的 iOS, Android 官方操做系統,鵝廠的工程師都在使用,快來加入咱們吧!