前言
我覺得開發(fā)技術(shù)的提升不僅僅是知識含量的增加,更重要的是開闊自己的思路椰憋,在解決同樣的問題時方案能夠更勝一籌到忽,讓程序能夠更有效率布讹,更優(yōu)雅率挣。這些思路往往都是在冥思苦想后的靈光一現(xiàn)刻伊。下面我舉幾個例子,包括 JSPatch 的方法調(diào)用思路椒功,微信讀書如何處理數(shù)據(jù)層卡頓捶箱,微信終端跨平臺組件 mars 里日志模塊 xlog 的性能優(yōu)化方案,以及自己在 SMCheckProject 項目中對使用方法的解析思路动漾。
JSPatch中的方法調(diào)用
JSPatch作者 bang 在 《JSPatch實現(xiàn)原理詳解》 這篇博客中提到方法調(diào)用的實現(xiàn)比如 UIView.alloc() 在開始時為了能夠讓這個方法調(diào)用丁屎,需要給 UIView 對象添加 alloc 方法。由于 JS 沒有 OC 那樣的轉(zhuǎn)發(fā)機制旱眯,所以 bang 開始的時候采用了一個復(fù)雜的方式晨川,在 require 生成類對象時通過類名用 Runtime 的方法找出此類所有方法,然后 JS 為每個方法生成一個函數(shù)键思,這樣的函數(shù)用方法名去 OC 調(diào)用對應(yīng)的方法。
這樣的想法可行甫贯,但是效率性能難以接受吼鳞,消耗的增長是指數(shù)級的。因為不光是當(dāng)前的類需要遍歷叫搁,父類直到頂層都需要赔桌,會出現(xiàn)內(nèi)存消耗過度的問題。后來 bang 苦苦找解決方案渴逻,突然腦洞大開疾党,想到如果能夠?qū)崿F(xiàn)調(diào)用一個不存在的方法能夠轉(zhuǎn)發(fā)到一個指定函數(shù)執(zhí)行就好了,于是把 JS 里方法調(diào)用都替換掉改成調(diào)用 __c() 函數(shù)惨奕,把相關(guān)信息傳給 OC 雪位,OC 再用 Runtime 來調(diào)用相應(yīng)的方法返回結(jié)果。這樣做不用遍歷梨撞,不用保存方法雹洗,我覺得這種腦洞大開想到的方案的這種思路是非常值得學(xué)習(xí),當(dāng)一種思路越陷越深時卧波,要時刻提醒自己时肿,跳出來再看看,是不是還有其它的路可以走港粱。
微信讀書處理數(shù)據(jù)層卡頓
在 WeRead團隊博客里有篇文章 《微信讀書 iOS 質(zhì)量保證及性能監(jiān)控》 介紹了他們對數(shù)據(jù)層的性能監(jiān)控螃成。他們數(shù)據(jù)層使用的是 YDataCenter,在這個數(shù)據(jù)層框架里一次 SQL 的完整操作要經(jīng)過等待 cache 隊列,放入 cache 隊列執(zhí)行寸宏,等待 db 隊列宁炫,放入 db 隊列四個步驟。將這四個步驟的時間和對應(yīng) SQL 記錄下來击吱,因為這樣的 SQL 操作較多淋淀,所以只將超過指定時間的記錄下來,這樣能以最小的代價找出那些造成阻塞卡頓的 SQL 和場景出來進行優(yōu)化覆醇。
日志文件寫磁盤導(dǎo)致大量IO引起程序卡頓
微信團隊在介紹他們微信終端跨平臺組件 mars 里的日志模塊時提到了他們對日志寫磁盤處理的考慮過程朵纷。一般的簡單的處理都會采取兩次數(shù)據(jù)拷貝實現(xiàn)寫入磁盤,第一次是從用戶空間內(nèi)存拷貝到內(nèi)核空間的緩存永脓,第二次是回寫內(nèi)核空間的緩存到磁盤袍辞。但是頻繁的空間切換使得應(yīng)用層的性能不可控。
一般為了解決空間切換都會采用先將日志緩存到內(nèi)存中常摧,達到設(shè)置的大小后再壓縮加密寫入文件搅吁,但是這個方案的壓縮還是會有讓 cpu 飆升的可能,還有個很嚴(yán)重的丟日志的問題落午。如何能夠完美處理呢谎懦。
mars 的日志模塊 xlog 最終采用了 mmap 這種內(nèi)存映射文件的方法來作為一個既能夠有直接寫內(nèi)存的性能,又具有直接寫文件可靠性的方案溃斋。從測試來看寫內(nèi)存和寫 mmap 的耗時幾乎是一樣的界拦。
SMCheckProject項目中對使用過的方法的解析
在 SMCheckProject 這個項目有需要解析出所有使用過的方法,一開始會想到使用遞歸梗劫,以前我做 STMAssembleView 中對自定義的 DSL 語言解析時就是使用的遞歸享甸,這樣時間復(fù)雜度就會是 O(nlogn) ,這次我換了個思路梳侨,將復(fù)雜度降低到了 n 蛉威,思路大概是 創(chuàng)建一個字典,鍵值就是深度走哺,模擬語法樹結(jié)構(gòu)蚯嫌,從左到右深度的增加根據(jù) [ 符號,減少根據(jù) ] 符號丙躏,值會在 [ 時創(chuàng)建一個 Method 結(jié)構(gòu)體齐帚,根據(jù) ] 來完成結(jié)構(gòu)體,將其添加到 methods 數(shù)組中 彼哼。 這種優(yōu)化在項目小文件少時看不出很大的區(qū)別对妄,但是在項目規(guī)模非常龐大時卻能將總時間省掉不少。
靈光一現(xiàn)后需要付出的努力
當(dāng)然光是有個好的思路和想法是完全不夠的敢朱,為了能夠?qū)崿F(xiàn)思路也是八方英雄各顯神通剪菱。從有了利用編譯原理中分析語法轉(zhuǎn)換語法這個思路進行動態(tài)化開始摩瞎,逐步演化到開發(fā)一套全自動編譯器實現(xiàn)OC源碼轉(zhuǎn)字節(jié)碼后通過自建虛擬機與Native運行時互聯(lián)。下面我列出些相關(guān)的文章孝常,可以看到大量的基礎(chǔ)知識積累是這些好的思路必備的基礎(chǔ)旗们,光是有著靈活的大腦也是不夠的。
- 用 Swift 搭建一個微型編譯器
- Antlr
- 從antlr扯淡到一點點編譯原理
- JSPatch Convertor 實現(xiàn)原理詳解
- JSPatch實現(xiàn)原理詳解
- Swift Playground微型編譯器
- 4種語言編譯器加字節(jié)碼虛擬機
- 如何著手看懂Clang Static Analyzer的源碼工作流程构灸?
- Swift: Challenges and Opportunity for Language and Compiler Research
- DynamicCocoa:滴滴 iOS 動態(tài)化方案的誕生與起航
- OCS——史上最瘋狂的iOS動態(tài)化方案 - 簡書