Hermes Engine初探

Hermes引擎是什麼,優點有哪些?

重要的事情提早說:Hermes引擎是Facebook研發,在React-Native Android端用於替換JavaScript Core的JavaScript引擎。Hermes引擎的優點是適合移動端的輕量級JavaScript引擎,使用aot編譯,能夠減小Android端內存使用,減少安裝包大小,提高執行效率。react

什麼是JavaScript引擎?

JavaScript引擎是一個專門處理JavaScript腳本的虛擬機,通常會附帶在網頁瀏覽器之中。android

主流JavaScript引擎

V8(Google)、JavaScriptCore(Apple)、SpiderMonkey(Firefox)react-native

RN中的JavaScript引擎

Weex,Android:V8,iOS:JavaScriptCore瀏覽器

RN,Android:JavaScriptCore(Hermes、V8),iOS:JavaScriptCore(Apple要求)babel

:Hermes Engine在React-native 0.60.2 版本後支持ide

Hermes的特點

  • 預編譯字節碼(引擎加載二進制代碼效率高於運行JS腳本)
  • 無JIT編譯器(減少了引擎大小,優化內存佔用,但直接運行JS腳本的性能差於V8和JSC)
  • 針對移動端的垃圾回收策略

優化原理

(截取自code.fb.com)性能

傳統JavaScript引擎一般是以上圖的模式完成代碼執行的,編譯階段只完成babel轉義和minify壓縮,產物仍是JavaScript腳本,解釋與執行的任務都須要在運行時完成(如V8引擎,還會在運行時將JavaScript編譯爲本地機器碼)很明顯缺點就是在運行時須要邊解釋邊執行,甚至須要佔用系統資源執行編譯任務。字體

image-20190729172843337

(截取自code.fb.com)gradle

Hermes引擎使用了aot編譯的方式,將解釋和編譯過程前置到編譯階段,運行時只完成機器碼的執行,大大提升了運行效率。優化

已有項目接入Hermes

  1. 升級React-Native及相關庫升級(成本較小)
  2. 由於React-Native 0.60.x變動爲依賴AndroidX,因此Android項目須要使用28以上版本編譯,適配Android高版本,且須要遷移到AndroidX(成本較大)
  3. 修改build.gradle,添加Hermes相關屬性及依賴(成本較小)

是否支持CodePush?

Hermes引擎預編譯後的產物與RN原方式相同,都是在assets文件夾下生成的index.android.bundle文件。RN原方式中index.android.bundle是通過壓縮的JavaScript腳本文件,Hermes預編譯後則是二進制文件。由於只有產物文件格式的區別,並無修改原有JS Bundle的加載方式,因此CodePush能夠繼續使用。

目前code-push的兩種發佈模式支持狀況:

發佈方式 是否支持 備註
code-push release-react 支持,但沒法產生預編譯腳本產物 需依賴react-native bundle命令完成腳本打包,該命令尚不支持預編譯
code-push release 支持

調試效率

Debug模式下Hermes不開啓預編譯以支持Hot Reload,缺點是Release模式下全部Hermes引擎優點都不存在,甚至由於無JIT致使性能還要差於原有引擎。但開發者模式並不追求性能,而更追求調試效率。

Debug模式內置libhermes-inspector.so,支持Chrome inspect的使用,支持DevTools協議,比原有RN調試體驗更佳(應用內代理,不能同步調試原生調用)

ES標準支持

Hermes支持ES6,緊跟最新的JavaScript規範。爲了優化引擎大小,不支持RN程序中使用較少的語言特性,如本地eval()。

性能調研

包大小分析

image-20190729174643389

(JSC引擎Release包)

image-20190729174736815

(Hermes引擎Release包)

原包大小20MB(JSC)

新包大小18MB(Hermes)

包大小減少2MB,總體減小2MB / 20MB = 10%

分析具體包大小減少的緣由能夠發現,包內容二者只有lib大小和assets的大小存在差別。

image-20190729174952340

(JSC引擎Release包)

image-20190729175007916

(Hermes引擎Release包)

對比lib內容,發現大小差距主要是由libjsc.so和libhermes.so二者的差距致使的,即Hermes引擎的大小。

image-20190729175354246

(JSC引擎Release包)

image-20190729175504457

(Hermes引擎Release包)

對比assets內容,發現大小變化主要由index.android.bundle,即JavaScript打包產物引發,Hermes模式下反而更大的緣由是進一步編譯爲二進制代碼。

二者影響疊加致使總體減少,包大小獲得優化。(支持的平臺越多,包體積優化效果越好)

內存分析

實驗方法:在相同的業務頁面穩定狀態下經過Memory Profiler查看內存佔用狀況

image-20190729150455599

(JSC引擎Release包)

image-20190729150430492

(Hermes引擎Release包)

原包平均內存佔用210MB

新包平均內存佔用190MB

內存佔用平均減少20MB以上,總體減少20MB / 210MB = 10%

分析Profiler數據能夠發現,內存優化主要發生在Code內存區。

image-20190729180820821

(JSC引擎Release包)

image-20190729180739358

(Hermes引擎Release包)

Google官方文檔中對內存Code區的描述

Code:您的應用用於處理代碼和資源(如 dex 字節碼、已優化或已編譯的 dex 碼、.so 庫和字體)的內存。

聯繫到上個章節中包大小分析中libhermes.so尺寸的減少,能夠很容易想到,內存佔用的減小就是由於.so對內存佔用的減少。另外二者對JavaScript內存的佔用也有細微差異,可是能夠忽略不計。

TTI性能

TTI:Time to Interactive,用戶可交互時間,啓動到頁面渲染完成而且能夠正常響應用戶的輸入的時間,衡量用戶體驗的移動端指標

React-Native Android中主要是Application onCreate開始到RN組件渲染完成可交互的時間。

值得吐槽的是,在iOS版本的Pref Monitor中直接就包含了這個指標的顯示,可是Android版本的Pref Monitor只有四個指標,且並無TTI這一指標。

在Android平臺上能夠經過RN提供的ReactFindViewUtil類獲取RN組件對應的原生組件,註冊對應的渲染回調,在控件渲染完成時記錄TTI結束時間。

image-20190729222910281

(JSC引擎Release包)

image-20190729222550135

(Hermes引擎Release包)

原包TTI 829ms

新包TTI 694ms

TTI減小135ms,總體減小135ms / 829ms = 16%

總結

面對Flutter的咄咄攻勢,React-Native終於作出了一些改變,Hermes做爲一款適合移動端的JavaScript引擎,確實有其性能優點,但願經過本文可以讓你更加了解Hermes。

相關文章
相關標籤/搜索