小程序這個名詞相信你們已經不陌生了,繼微信以後,阿里巴巴、百度、頭條等大廠相繼實現了本身的小程序。小程序是一種全新的開放能力,開發者可以快速開發出小程序並集成進宿主,實現推廣等目的。
從使用角度看,小程序有輕量,易用等特色;
從技術角度,以Android端爲例,小程序有部分組件原生化、UI和邏輯線程隔離、小程序之間進程隔離等等。java
本篇文章主要從小程序進程隔離角度出發,分析BAT的小程序多進程的實現方案,並本身實現一個小程序的多進程。git
若是有朋友須要從頭開學,那就能夠分享我整理好的內容 小程序開發教程github
多進程,顧名思義,即每個小程序都是一個單獨的進程。這個效果只在Android端獨有。那爲何咱們但願小程序之間實現進程隔離呢?緣由大體有三點:web
因爲是單獨進程,不管小程序內部由於何種緣由的崩潰,對主進程都沒有影響,加強用戶體驗。面試
因爲每一個進程都有一片單獨的內存區域,小程序不會佔用主進程的內存,下降了內存溢出的風險。算法
##對微信小程序的分析
既然是分析多進程這種用戶感知不強烈的技術點,咱們須要經過一些工具或命令。shell
進程分析 小程序
首先,咱們把微信徹底殺死又從新開啓,而後經過 adb shell ps | grep com.tencent.mm 命令,能夠查看正在運行的進程名稱和數量,其中 grep com.tencent.mm 是過濾微信相關的進程,由於微信的包名是com.tencent.mm。此時進程運行情況以下圖:微信小程序
此時咱們只能看出微信從徹底關閉到啓動,開啓了6個進程,可是還看不出這些是否與小程序相關。因而,咱們打開一個小程序,再次執行 adb shell ps | grep com.tencent.mm 命令,此時進程運行情況以下圖:性能優化
對比以後,就能夠作一些分析了。其中,com.tencent.mm是主進程,com.tencent.mm:push應該是與推送相關的進程,com.tencent.mm.tools和com.tencent.mm:toolsmp應該都是一個相似於Helper的相關進程,所以我認爲最有可能的是com.tencent.mm:appbrand2,由於這個命名比較特殊,前面分別有appbrand0和appbrand1兩個進程出現過。那麼爲何新開的第一個小程序,反而多出來的進程時appbrand2呢?我我的猜想這與微信小程序的預加載有關係,頗有多是,這個進程是空的,只是先fork出來,並無作過多的事情,真正承載咱們開啓的那個小程序的進程,頗有可能不是這個appbrand2。那麼如何驗證呢?進入第二步,Activity分析。
#####Activity分析
首先打開一個小程序,而後經過 adb shell dumpsys activity activities 命令,能夠看到全部棧內的Activity信息,滑到頂部,查看正在與用戶交互的Activity信息,以下圖:
關鍵的信息我已經用紅色圈了出來,processName=com.tencent.mm:appbrand0,realActivity=com.tencent.mm/.plugin.appbrand.ui.AppBrandUI,這大體已經驗證了咱們剛纔的猜測,即:
com.tencent.mm:appbrand系列,是與小程序相關的進程。
爲了進一步驗證猜測是否正確,我下載了微信最新版本的apk,進行了逆向操做,也就是第三步,分析apk。
##### 微信Apk分析
反編譯的方法你們自行搜索,這裏就不贅述了。咱們打開反編譯後的AndroidManifest.xml文件,搜索剛纔的的Activity名稱,結果以下:
獲得的信息與剛纔一致。然而,咱們又發現了另外一個問題,那就是AppBrandUI還有另外4個兄弟,即AppBrandUI1,AppBrandUI2,AppBrandUI3,AppBrandUI4,而這四個Activity的名稱與綁定的進程,又可以與一開始的appbrand對應起來,通過試驗,我發現微信最多隻能夠啓動5個小程序,而這些小程序的載體就是這5個Activity,不斷輪詢,超過5個時,將第一個結束掉。這樣,咱們就基本能夠肯定,微信是經過apk內置的5個Activity,來實現小程序的多開與進程隔離的。
所以,理論上這5個Activity應該是除了進程不一樣,內部邏輯應該都是相同的,因而咱們繼續驗證,反編譯代碼後找到AppBrandUI1這個Activity,結果以下圖:
AppBrandUI2,AppBrandUI3,AppBrandUI4與此徹底同樣,都是繼承了AppBrandUI,作了極少的事,因爲微信代碼混淆過,咱們沒法看出那幾行代碼具體作了什麼,可是基本能夠理解爲徹底複用。至於爲何分開寫,而不是複用同一個,我猜想緣由可能有二:
1. 因爲語法限制,爲Activity開闢進程須要在AndroidManifest.xml中預先配置
2. 微信不只將小程序進程隔離,而且還進行了棧隔離,當咱們同時開啓多個小程序時,長按Home鍵,能夠發現存在多個小程序任務卡片,這種效果一樣須要在AndroidManifext.xml中配置taskAffinity屬性,這在上圖中也有體現。
另外,我還注意到,微信在AndroidManifest.xml中配置了這樣的Receiver:
這種Receiver共有5個,每一個小程序進程有一個,其它4個只是繼承了這個AppBrandTaskPreloadReceiver,因爲混淆的緣由,沒法看出具體作了什麼事,可是經過名字判斷,是實現小程序進程預加載的,空閒時開啓這個廣播,至少能夠提早開啓進程,避免用時再加載耗時過長影響用戶體驗。
一樣的,我分析了百度和支付寶的apk,經過命令和反編譯等方法,發現他們的方案几乎同樣,只是預加載的數量等一些小細節不一樣,感興趣的同窗能夠本身逆向以後作對比。
分析總結
1. 微信對每一個小程序都作了進程隔離和棧隔離,互不影響。
2. 實現這一功能的載體Activity是預先配置在AndroidManifest.xml中的。
3. 經過某種方法,微信將小程序的最大運行數量控制在5個。
4. 微信對多進程作了一些優化,已知的是預加載2個空進程。
5. BAT等大廠的小程序多進程方案大同小異。
一. Application初始化
Android的app在開啓多進程時,每開啓一個進程,Application都會從新建立,也就是onCreate函數會被調用,若是沒有作進程判斷,全部東西會初始化屢次,形成卡頓或意料以外的bug。
二. 分配與管控
因爲進程之間的內存沒法共享,小程序的生命週期須要在某一個進程中維護,否則沒法作到動態分配進程和棧,而這個進程選擇主進程最爲合適。所以須要建立一個管理器,這個管理器負責如下幾件事:
1. 接收外界開啓、關閉等對小程序的操做
2. 合理的爲接收到的請求分配空閒的進程
3. 接收遠程小程序的生命週期回調並經過某個uuid進行維護
4. 在空閒時預加載進程
5. 根據設置的可開啓的最大小程序數量,對進程進行新建、銷燬等操做
6. 全部這些管理和維護的操做,對小程序接入者都應是透明的,無需關心具體實現流程,僅在須要時開啓小程序便可。
三. 進程生命週期問題
Android系統對於內存有一套本身的管控機制,當內存較爲緊張時會在不作任何通知的狀況下kill掉活躍度較低的進程,至於進程活躍程度,就與Android的進程保活有關了,可經過設置前臺進程、喚醒等方式去儘可能保活。可是不管應用端再怎麼作,都沒法逾越操做系統的權限,系統在某些狀況下依然會把進程殺死來保證整個系統的正常運行。所以,開發時須要作容錯處理,不能僅以Activity的onDestroy回調爲準,由於一旦出現系統級的回收,極可能致使整個分配管理器的錯亂。
四. 通信
通訊又分爲兩個方面,第一,小程序進程與app主進程是隔離的,須要進程間的IPC通訊;第二,小程序的本質是一個web容器,這就少不了js與原生的通訊,須要jsbridge。下面分別說一下這兩個方面。進程通訊:
IPC的實現已經不是什麼問題,這裏僅說幾個須要注意的點:
1. 通訊必定是雙向的,不管哪一個進程,最好綁定同一個服務,方便數據的維護。
2. 因爲通訊較爲頻繁,建議使用基於Binder的通訊機制,能夠提升運行效率。
js與原生通訊:
js與原生通訊必定是經過jsbridge,最好作法是將原生方法的實現寫在主進程,分佈在不一樣進程的小程序向主進程請求某個bridge的實現結果,主進程根據相應的參數去執行並返回結果,相似於一套CS的架構。即小程序客戶端無需關心具體操做,只關心結果並響應給web端。
###結語
認真分析以後發現微信小程序作的優化仍是不少的,從xml中還能夠看出一些代理類等等。我我的得出的結論大概就是這些,歡迎指正和補充,謝謝!
BATJ、字節跳動面試專題,算法專題,高端技術專題,混合開發專題,java面試專題,Android,Java小知識,到性能優化.線程.View.OpenCV.NDK等已經上傳到了的個人GitHub
你們點擊個人GitHub地址:https://github.com/Meng997998/AndroidJX點下star一塊兒學習