說說 方舟編譯器

秉心說發表於2019-04-12

說說 方舟編譯器

華為繼去年推出黑科技 GPU Turbo 之後,今年再次扔出了一枚重磅炸彈, 安卓效能革命,華為方舟編譯器,號稱解決安卓程式 “邊解釋邊執行” 的低效,全程執行機器碼高效執行程式。架構級優化,顯著提升效能。系統操作流暢度提升 24%,系統響應提升 44%,三方應用操作流暢度提升 60%,並承諾向業界開源。敢於開源的話,這個資料應該沒有水分。大家在網上應該也看到了 P30 Pro 吊打 S10 的視訊。

解決安卓程式 “邊解釋邊執行” 的低效,什麼是邊解釋邊執行?也就是說,Android 是如何執行 Apk 中的程式碼的?這得從機器碼說起。

機器碼

不論是低階語言,如彙編,還是如今廣泛使用的各種高階語言,Java,C++ 等,對於 CPU 來說,全部都是天書。它能認識的只有二進位制的機器碼。當然,機器碼對你來說,也是天書。那你應該如何指揮 CPU 執行你的程式呢?這個時候,你們之間就需要一個翻譯,將你的程式碼翻譯成機器碼給 CPU,它就知道該如何執行了。面對不同的終端,翻譯內容也不一樣,你一個只知道 x86 指令集的去翻譯 arm 的,肯定翻譯不出來,就好似拿著本英語字典去翻譯日語。翻譯也有工具,下面說說幾種常見的翻譯工具:

彙編器

將彙編程式碼直接翻譯成機器碼。由於彙編程式碼一般和機器碼都是一一對應的,所以它的速度非常快。只是組合語言,你懂的,可讀性差, 用起來難,用來寫大型程式對於普通開發者基本是不現實的。

編譯器

編譯器將我們平常開發用的高階語言,例如 Java/C++ 等,翻譯成機器碼供 CPU 使用。這種編譯很慢,但是執行起來會很快。

直譯器

程式不需要編譯,程式在執行時才翻譯成機器語言,每執行一次都要翻譯一次。因此效率比較低。可以想象這種執行方式就慢了很多。 典型的解釋型語言,php/js/python 等。

JAVA 程式碼是如何執行的 ?

Java 程式的執行依賴於 Java 虛擬機器(JVM),JVM 能直接識別的叫做位元組碼。Java 程式碼經過編譯會生成 Class 檔案,即位元組碼檔案,再交由 JVM 處理。而 JVM 又是怎麼執行 Class 檔案的呢?這裡以 HotSpot 為例,Class 檔案被虛擬機器載入後會存放在方法區,實際執行時,虛擬機器會執行方法區中的程式碼。

將位元組碼翻譯成機器碼的工作自然就由 JVM 來承擔了。在 HotSpot 中,有幾種翻譯形式。

  • 解釋執行

逐條將位元組碼翻譯成機器碼並執行

  • 即時編譯(Just-in-time ,JIT)

將一個方法中包含的所有位元組碼編譯成機器碼後再執行。

前者的優勢在於無需等待編譯,而後者的優勢在於實際執行速度更快。HotSpot 預設採用混合模式,綜合瞭解釋執行和即時編譯兩 者的優點。它會先解釋執行位元組碼,而後將其中反覆執行的熱點程式碼,以方法為單位進行即時編譯。

Android 程式碼是如何執行的 ?

開發 Android 目前用的最多的還是 Java,即使不是 Java,也是 JVM 語言。Android 工程中的 java 原始檔經過編譯也是生成 Class 檔案,最後被打包成 DEX 位元組碼檔案,負責將 DEX 位元組碼翻譯成機器碼的是 Dalvik 或者 Art。

在 Android 5.0 之前,還是 Dalvik 的天下。Dalvik 是解釋執行加上 JIT,每次app執行的時候,它動態的將一部分 Dalvik 位元組碼 解釋為機器碼。隨著 App 的執行,更多的位元組碼被編譯和快取。因為 JIT 只編譯了一部分程式碼,它具有更小的記憶體佔用和更少的裝置物理空間佔用。但是,邊解釋邊執行,效率低下,這也是後來 Dalvik 遭到拋棄的原因。

從 Android 4.4 開始,Android 引入了 Art,到 Android 5.0,Art 正式代替了 Dalvik。Art 使用的是 AOT(Ahead of Time)的編譯方式,即在應用的安裝過程中,就將所有的 Dex 位元組碼翻譯成機器碼儲存在裝置空間中,完全拋棄了 JIT,帶來的好處是顯而易見的。

  • Apps 執行的更快,因為 DEX 位元組碼的解釋在安裝過程中已經完成,直接執行機器碼

  • 減少了應用的啟動時間,因為原生程式碼可以直接執行。

  • 節省電量消耗,不需要再去一行一行的解釋位元組碼。

  • 增強了垃圾回收。

  • 增強了開發者工具。

直接執行機器碼,恩,等等,這不就是方舟編譯器做的事情嗎?答案肯定是否定的,否則它因為完全沒有存在的必要了。事實上,這種完全基於 AOT 的模式也已經被 Android 拋棄了。如果你用過 5.0 或者 6.0 的安卓機,你一定不會忘記安裝應用帶來的漫長等待。由於需要在安裝期間翻譯位元組碼,所以安裝過程會很長,尤其對 一些大型應用來說。另外,安裝過程中翻譯出來的機器碼也佔用了更大的機身儲存空間。

Android 7.0,Android 又加入了 JIT,一個具備程式碼分析功能的即時 (JIT) 編譯器。事實上,根據二八定律,經常執行的熱點程式碼可能只佔 20%,甚至更少,我們沒有必要通過 AOT 提前將所有位元組碼都翻譯成機器碼。安裝過程中放棄 AOT,加快安裝速度,所以初次使用時得解釋執行。當你在使用應用時,JIT 就開始分析程式碼了,在合適的時候將位元組碼翻譯成機器碼,在 Android 應用執行時持續提高其效能。另外,裝置空閒的時候,AOT 就發揮作用了,它會將熱點程式碼翻譯成機器碼並儲存下來,進一步提高執行效率。這麼看下來,現在的 Android 是 解釋執行 、JIT、AOT 同時存在的。下面這張官網的圖片很好的說明了Art 下的 JIT 架構.

說說 方舟編譯器

關於直譯器,高版本中的 Android 實現也不再那麼孱弱了,根據官網相關介紹:

通過引入 Mterp(一種直譯器,具有以組合語言編寫的核心提取/解碼/解釋機制),Android 7.0 版本中的直譯器效能得以顯著提升。Mterp 模仿了快速 Dalvik 直譯器,並支援 arm、arm64、x86、x86_64、mips 和 mips64。對於計算程式碼而言,ART 的 Mterp 大致相當於 Dalvik 的快速直譯器。 不過,有時候,它的速度可能會顯著變慢,甚至急劇變慢:

  • 呼叫效能。
  • 字串操作和 Dalvik 中其他被視為內嵌函式的高頻使用者方法。
  • 堆疊記憶體使用量較高。

Android 8.0 解決了這些問題。

說了這麼多,無非是安裝速度,空間佔用,執行速度的平衡,目前 Android 應該已經做得很好了,但仍然存在不少詬病。

現在可以確定的是,方舟編譯器絕對不可能是 完全 AOT。PPT 中最後一句話是 “希望 APP 廠商儘快使用” ,並不是手機廠商,所以不排除方舟編譯器可以直接將 Apk ,或者說 Apk 中的 DEX 打包成機器碼格式。但由於機器碼並不是平臺相容的,所以並不能確定方舟編譯器是否必須要繫結 EMUI。其實說到底,這一切都應該是為了華為的新手機系統作鋪墊。華為的野心之大,以及其極其超前的技術儲備,相信一個完整華為生態已經離我們不遠了。

編譯器叫方舟,新系統乾脆就叫 諾亞 吧!

文章首發於微信公眾號: 秉心說 , 專注 Java 、 Android 原創知識分享,LeetCode 題解,歡迎掃碼關注!

說說 方舟編譯器

相關文章