2017年5月的一個(gè)凌晨,華為某實(shí)驗室里,方舟編譯器上第一個(gè)Java程序“Hello, World”跑通了。

當時(shí)項目組的一位工程師就哽咽了:“I never thought printing ‘Hello, World’ would be this hard .”(我從來(lái)沒(méi)想到打出“Hello, World”會(huì )如此艱難。)
十年前華為啟動(dòng)編譯組到這一刻,初見(jiàn)曙光。
2019年4月,華為方舟編譯器正式面世!
今天我們聚焦華為新貴——方舟編譯器,這個(gè)一發(fā)布就引起巨大響動(dòng)的底層核心技術(shù)。
它為什么能擁有和世界對話(huà)的榮光?
它承載著(zhù)怎樣的使命?
它能否做到傳說(shuō)中的“出于安卓,勝于iOS”?
1. 機器的“原力覺(jué)醒
這個(gè)故事,先從計算機的語(yǔ)言說(shuō)起。
事實(shí)上,人類(lèi)文明中最早出現的文字就是數字,比完整表意的文字早500-1000年。
隨著(zhù)人類(lèi)社會(huì )的發(fā)展,社會(huì )結構開(kāi)始變得復雜,征稅必須先收集國民收入、財產(chǎn)、付款、欠款、債務(wù)、罰款等數據,遠遠超過(guò)人腦的記憶系統。于是,數字誕生了。
5000年前,蘇美爾人文明(今科威特及鄰近地區)以6和10作為基數,用符號表達1、10、60、600、以及3600。今天,我們仍然常見(jiàn)以6為基數的數字,例如圓有360度,一天有24小時(shí)。
而另外一種叫安第斯文化(主要在今天的南美地區),則用“結繩語(yǔ)”記錄數字,管理稅收等財務(wù)數據長(cháng)達數百年甚至數千年。就算西班牙人占領(lǐng)南美之后,還在相當一段時(shí)間內用結繩語(yǔ)來(lái)管理他們建立的新帝國。

這就是人類(lèi)最早的語(yǔ)言,雖然不能完整傳遞口語(yǔ),也無(wú)法寫(xiě)詩(shī),但是記賬收稅效率一流。
公元8世紀,印度人發(fā)明了數字0-9,這種十進(jìn)制的數學(xué)符號讓數據存儲和處理的效率一日千里,成為人類(lèi)文明重要的里程碑,奠定了現代數學(xué)基礎。后因阿拉伯人將其發(fā)揚光大并傳入中東和歐洲,所以大家稱(chēng)之為“阿拉伯數字”。
還有一種文字系統——“0”和“1”的二進(jìn)制,是人類(lèi)文明另外一個(gè)重要的里程碑,被廣泛應用在現代計算機領(lǐng)域中。此外,我們喜歡的音樂(lè )、我們熱愛(ài)的電影、我們拍攝的照片,今天都是通過(guò)這種二進(jìn)制的數字來(lái)進(jìn)行“重現”,包括記錄、存儲、傳播和分享。
人類(lèi)通過(guò)0和1開(kāi)啟了機器“文明”,從此科學(xué)革命的進(jìn)程就像安裝上了“火箭”。
那為什么計算機使用的是二進(jìn)制呢?
這個(gè)故事得回溯到大英帝國的航海時(shí)代。
早在17世紀,英國借助強大的經(jīng)濟實(shí)力和海軍力量擁有了眾多的殖民地,建立了全球霸主地位。艦隊使用的航海表計算復雜,人工計算的數據經(jīng)常有誤,百年間導致大量的船只觸礁沉沒(méi)。
直到第一次工業(yè)革命爆發(fā),英國政府找到了數學(xué)家巴貝奇(Charles Babbage)來(lái)修正航海表。巴貝奇通過(guò)十年的努力,研制成功了“差分機”。用蒸汽機時(shí)代的機械齒輪來(lái)存儲計算過(guò)程中的數據,大大提升了航海表數據的計算速度和準確率。
同期,他開(kāi)始了另外一種新機器——分析機的設計。在開(kāi)發(fā)分析機的過(guò)程中,巴貝奇冥思苦想,發(fā)現乘法是加法的重復,除法是減法的重復,減法可以用加法來(lái)代替,這樣就只要設計一個(gè)加法運算器即可。基于這種假設,計算機器只需要具備兩個(gè)功能即可運作:
- 判斷兩個(gè)數的大小;
- 不斷重復執行加法計算。
所有的運算轉化為最簡(jiǎn)單的判斷和計算,1表示Yes(開(kāi)),0表示No(關(guān)),計算機用0和1不斷重復計算。這就是計算機使用“0”和“1”二進(jìn)制語(yǔ)言的理論基礎。
值得一提的是,巴貝奇發(fā)明分析機不久之后,英國數學(xué)家喬治·布爾于1854年發(fā)表了“布爾代數學(xué)”,提出了邏輯學(xué)的二元運算,為現代電子計算機提供了另外一個(gè)重要的理論基礎。
回到分析機,巴貝奇借鑒了法國紡織機上使用的穿孔卡片。卡片上的孔眼排列,控制紡織機的梭子,能夠不斷重復的織出各種各樣美麗圖案的布匹。巴貝奇在著(zhù)名詩(shī)人拜倫之女Ada Lovelace的幫助下,發(fā)現穿孔卡片不僅可以用來(lái)記錄數據,還能用來(lái)控制機器工作的指令。在卡片上打上不同排列的孔,機器便有不同的工作程序,這就是現代計算機的軟件設計思想。
基礎研究與基礎教育是產(chǎn)業(yè)誕生和振興的根本。這也是為什么今天的英國,仍然在數學(xué)和通信領(lǐng)域擁有非常廣泛的影響力。
1884年,美國統計專(zhuān)家赫爾曼·何樂(lè )禮(Herman Hollerith)借鑒穿孔卡原理發(fā)明了電動(dòng)制表機,用于美國人口統計,與巴貝奇的分析機具有異曲同工之妙。他把所有需要調查的項目依次固定在一張硬紙卡上,然后將統計的居民個(gè)人信息在相應位置打孔,用來(lái)表示“Yes”。當統計機器的探針撞到卡片上的“孔”,就會(huì )接通電流,計數裝置往前進(jìn)一個(gè)刻度。何樂(lè )禮博士正是采用了二進(jìn)制的原理,來(lái)高效統計美國人口信息。
我們今天使用的答題卡,就采用了這種原理。

何樂(lè )禮博士隨后創(chuàng )建了制表機公司,也就是赫赫有名的IBM公司的前身。
1935年,著(zhù)名的現代計算機科學(xué)之父和人工智能之父,艾倫·圖靈提出了著(zhù)名的圖靈機模型,為現代計算機的邏輯工作方式奠定了理論基礎。
1937年,美國哈佛大學(xué)著(zhù)名計算機專(zhuān)家霍德·艾肯在IBM公司的資助下,借鑒上面提到的英國數學(xué)家巴貝奇的分析機理論,于1944年研制成功世界第一臺機電計算機——Mark-I型。IBM把這臺計算機送給了哈佛大學(xué),并一直使用到1959年,為培養早期的計算機科學(xué)家做出了巨大貢獻。
另外一位學(xué)者就沒(méi)有這樣幸運了。美國愛(ài)荷華州立大學(xué)理論量子物理學(xué)的約翰·阿塔那索夫(John Atanasoff)副教授,苦于沒(méi)有機器能夠計算出量子物理中許多變量的求解。同樣是在1937年,他尋求IBM公司的資助,但被斷然拒絕,于是他橫下決心一定要研制一臺更好的計算機器。他利用當時(shí)正在發(fā)展的真空晶體管,用電子脈沖來(lái)表示“0”和“1”,并在電氣工程專(zhuān)家克利福特·貝瑞(Clifford Berry)的幫助下,兩人于1940年底研制成功了世界第一臺電子計算機,并用兩個(gè)人的名字將其命名為ABC(Atanasoff-Berry Computer)。
阿塔那索夫開(kāi)辟了一種計算機的全新路徑,為現代電子計算機的架構奠定了不可磨滅的基礎。今天的華為在內部強調研發(fā)上要多路徑突破,或許也曾受此啟發(fā)。
1940年底,他結識了美國物理學(xué)家莫克利(JohnW.Mauchly)。莫克利在了解和參觀(guān)了ABC計算機后,聯(lián)合賓夕法尼亞大學(xué)莫爾學(xué)院的電氣專(zhuān)家艾克特(J.PresperEckert),在國防部的資助下和馮·諾依曼博士的指導下,于1945年研制成功了世界第一臺通用電子計算機ENIAC。雖然這臺計算機采用的是十進(jìn)制,但當時(shí)毫不影響它的計算能力,它大大縮短了美國“曼哈頓計劃”的原子彈研發(fā)時(shí)間,加速了二戰的結束。
1945年6月,馮·諾依曼將ENIAC電子計算機的十進(jìn)制改回成二進(jìn)制,并提出計算機內部存儲器存儲程序的概念,從而奠定了現代電子計算機理論的架構。
0和1這種極簡(jiǎn)的語(yǔ)言設計,像給計算機注入了永遠在生長(cháng)的“原力”,帶來(lái)了無(wú)限的可能。與通信領(lǐng)域IP路由理念具有異曲同工,就像“看不見(jiàn)的蒸汽機”,用最簡(jiǎn)單的理論架構開(kāi)啟了一個(gè)全新的偉大產(chǎn)業(yè)。
2. 軟件王國的“四大明珠
實(shí)際上,在電子計算機誕生之前,計算機這個(gè)角色是由女人來(lái)扮演的。這些女人被稱(chēng)為Computers,大多數計算都是她們手工完成的。
世界第一段程序,是上面提到的巴貝奇的師妹著(zhù)名詩(shī)人拜倫之女Ada Lovelace在打孔卡上寫(xiě)出來(lái)的。程序設計人員都要把程序編排成010101這樣的形式,在紙上打孔,再送到機器里去讀。這減少了相當多的工作,寫(xiě)一個(gè)卡片能使用相當久,也避免了重復造輪子。
因此,當程序員開(kāi)始在卡片上寫(xiě)這些程序時(shí),人們開(kāi)始構建程序庫(libraries)。隨著(zhù)時(shí)間的推移,大部分的程序漸漸的有了一些規則手冊來(lái)指導編寫(xiě)。但還是很繁瑣,畢竟編寫(xiě)和記憶0和1的各種組合,對于很多人來(lái)說(shuō)相當于是“天書(shū)”。
一個(gè)傳奇的人物出現了。
美國海軍的傳奇天才格雷斯·霍珀(Grace Hopper),在海軍服役時(shí),曾被派到哈佛大學(xué),與艾肯博士一起工作,負責為美國國防部資助的Mark-II型機電計算機編制程序。在二戰結束后,她加入了發(fā)明ENAIC電子計算機的莫克利和艾克特創(chuàng )辦的“電子控制公司”,開(kāi)始了她改變世界的光輝旅程——打開(kāi)編譯器和編程語(yǔ)言的新世界。

Grace在加入莫克利和艾克特的公司,便產(chǎn)生了一種想法。她想設計一種程序,讓人可以用類(lèi)似英文的語(yǔ)法,把想做的事寫(xiě)下來(lái),然后用這個(gè)程序把英文翻譯成機器能執行的語(yǔ)言,交給機器去執行。
她把這個(gè)革命性的想法付諸實(shí)踐,發(fā)明了世界上第一個(gè)編譯器A-0。這是編譯器的始祖,也是現代編程語(yǔ)言的始祖。
1952年,Grace和莫克利研究出了一種較為接近自然語(yǔ)言的計算機語(yǔ)言——匯編語(yǔ)言Flow-Matic。匯編語(yǔ)言本質(zhì)上是使用助記符來(lái)代替機器語(yǔ)言01010101,進(jìn)了一大步,但這種語(yǔ)言對計算機硬件依賴(lài)很大。不同的計算機,匯編語(yǔ)言不相通。
IBM公司在1946年后從制表機全面轉型電子計算機市場(chǎng),并投入巨資招攬了世界眾多頂尖的計算機人才。其中一位叫約翰·貝克斯(John W. Backus),這位出身證券經(jīng)紀人家庭的富二代,酷愛(ài)數學(xué),加入IBM公司三年后,發(fā)明了一種快速編程的FORTRAN語(yǔ)言。同時(shí),他深入研究了Grace發(fā)明的Flow-Matic的編譯器,應用到FORTRAN的編譯器中。
FORTRAN的問(wèn)世,在計算機史上具有劃時(shí)代的意義。它是世界第一個(gè)高級編程語(yǔ)言,使計算機語(yǔ)言從原始的低級匯編語(yǔ)言走到人人易懂的境界,計算機不再是科學(xué)家的專(zhuān)利**。**FORTRAN的誕生,孕育了軟件產(chǎn)業(yè)。此后,計算機高級編程語(yǔ)言進(jìn)入蓬勃發(fā)展的時(shí)代。
隨后,IBM公司開(kāi)發(fā)出了的ALGOL高級語(yǔ)言,人工智能之父約翰·麥卡錫(John McCarthy)發(fā)布了人工智能設計語(yǔ)言L(fǎng)ISP,Grace奶奶也在Flow-Matic匯編語(yǔ)言的基礎上開(kāi)發(fā)了COBOL語(yǔ)言。
FORTRAN適合科學(xué)計算,ALOGOL適合事務(wù)處理,LISP適合人工智能計算,COBOL適合商業(yè)處理。這四種高級語(yǔ)言雖然比匯編語(yǔ)言更簡(jiǎn)單,但對于非計算機專(zhuān)業(yè)人員,編程仍難度較大。于是,Dartmouth學(xué)院的兩位教授聯(lián)手開(kāi)發(fā)一種更簡(jiǎn)單的編程語(yǔ)言BASIC(初學(xué)者的全方位符式指令代碼)。這是一種不需要編譯的語(yǔ)言,只需要經(jīng)過(guò)解釋器執行即可,初期的Android智能手機軟件借鑒了這種機制。BASIC語(yǔ)言也是目前被廣泛使用的Visual Basic語(yǔ)言的鼻祖,目前在微軟Excel的“宏”中可以直接使用。
美國編程語(yǔ)言的開(kāi)發(fā)熱潮你追我趕,其他國家也不甘示弱。
1963年,英國劍橋大學(xué)推出了CPL語(yǔ)言,后又推出了簡(jiǎn)化的BCPL語(yǔ)言。
1970年,美國貝爾實(shí)驗室的肯·湯普遜(Ken Thompson)和丹尼斯·利奇(Dennis Ritchie)在BCPL語(yǔ)言的基礎上,推出了更加簡(jiǎn)單的B語(yǔ)言(取BCPL第一個(gè)字母),后又簡(jiǎn)化出了C語(yǔ)言(取BCPL第二個(gè)字母)。這是目前世界上最常用的編程語(yǔ)言之一,甚至可以說(shuō)是第一大編程語(yǔ)言。
C語(yǔ)言之后,誕生了很多著(zhù)名的語(yǔ)言,包括:
C++:1983年正式發(fā)布。由貝爾實(shí)驗室基于C語(yǔ)言改良,所以C++是完全兼容C語(yǔ)言的。
Objective-C:1980年代發(fā)明。1988年,斯蒂夫·喬布斯(Steve Jobs)在NeXT公司時(shí)買(mǎi)下了 Objective-C 語(yǔ)言的授權,后來(lái)成為蘋(píng)果公司MAC電腦和iPhone手機的程序設計語(yǔ)言。
Java:1995年5月發(fā)布。SUN公司為了在電視機頂盒等電子產(chǎn)品智能化過(guò)程中搶占先機,解決跨平臺的問(wèn)題,所以開(kāi)發(fā)了Java語(yǔ)言。但Java需要借助虛擬機機制來(lái)解釋源代碼并調度硬件資源。安卓系統使用的基礎語(yǔ)言就是Java。
C#:2000年6月,由微軟發(fā)布。C#與Java有著(zhù)驚人的相似,也需要借助類(lèi)似于虛擬機的Framework來(lái)運行;不同的是,Java支持所有平臺,而C#只支持Windows和Linux系統。
GO:谷歌在2009年發(fā)布。GO語(yǔ)言主要用作服務(wù)器端和云計算開(kāi)發(fā)。
Swift:2014年由蘋(píng)果公司發(fā)布,可以和Objective-C語(yǔ)言混合使用。
其中,C/C++是編譯語(yǔ)言,即在程序員寫(xiě)完程序后,通過(guò)編譯器直接編譯成機器碼,安裝到相應的硬件設備上即可直接運行。
Java/C#是預編譯語(yǔ)言,就是需要先在開(kāi)發(fā)者環(huán)境中將源代碼(Source Code)轉換成字節碼(Byte Code),然后在設備上運行時(shí)再將字節碼編譯或解釋成硬件能聽(tīng)得懂的機器碼。將源代碼轉換成字節碼的過(guò)程,就叫預編譯。

軟件王國還有兩個(gè)很重要的成員,就是操作系統和數據庫。
上個(gè)世紀60年代,計算機高級語(yǔ)言的發(fā)展為操作系統和數據庫的誕生培育了沃土。
1970年,貝爾實(shí)驗室B語(yǔ)言和C語(yǔ)言的開(kāi)發(fā)者肯·湯普遜(Ken Thompson)和丹尼斯·利奇(Dennis Ritchie),開(kāi)發(fā)出了世界第一個(gè)通用計算機系統——UNIX。現在大家熟悉的Linux和Mac OS就是類(lèi)UNIX操作系統。
其中Linux可以運行在服務(wù)器和其他大型平臺之上,如大型計算機和超級計算機,世界上最快的前10名超級計算機運行的都是基于Linux內核的操作系統。在移動(dòng)設備上廣泛使用的Android操作系統也是創(chuàng )建在Linux內核之上。
隨著(zhù)磁盤(pán)的發(fā)明,從磁盤(pán)隨機存取數據成為可能。1961年,美國通用電氣公司成功地開(kāi)發(fā)出世界上第一個(gè)數據庫管理系統(DBMS)——IDS(Integrated DataStore 集成數據存儲)。1968年,IBM公司開(kāi)發(fā)了IBM第一個(gè)數據庫系統IMS(Information Management System)。IBM科學(xué)家的論文理論,成就了著(zhù)名的Oracle數據庫。IBM公司出品的DB2和微軟公司的MS SQLServer數據庫也成為當今數據庫領(lǐng)域重要的角色,目前在全世界已經(jīng)廣泛應用。
高級編程語(yǔ)言、編譯器、操作系統和數據庫,被稱(chēng)為軟件王國的“四大明珠”。

從上圖可以看出,為軟件底層貢獻核心技術(shù)的公司主要來(lái)自于歐美。華為通過(guò)多年持續的研發(fā)投入,讓我們終于看到了美國巨頭的背影。
3. 編譯器的前世今生
如果說(shuō)計算機是汽車(chē),那么軟件就像汽車(chē)的操控系統一樣,是計算機的血液。
編譯器則是汽車(chē)發(fā)動(dòng)機里最核心的汽油燃燒技術(shù),將軟件變成計算機的動(dòng)力,其編譯性能和效率,直接決定了用戶(hù)的使用體驗。
如上文所述,最早的編譯器是Grace奶奶發(fā)明的A-0編譯器。
第二個(gè)被大規模應用的編譯器,則是和FORTRAN編程語(yǔ)言配套的FORTRAN編譯器。
目前主流使用的編譯器主要有下面幾種:
Windows系統
使用CL編譯器。它直接集成在Visual Studio或Visual C++的開(kāi)發(fā)者環(huán)境中,一般不單獨使用。
Linux系統
使用開(kāi)源的GCC編譯器。GCC,由自由軟件運動(dòng)的精神領(lǐng)袖理查德·馬修·斯托曼(Richard Matthew Stallman, RMS)在上個(gè)世紀80年代創(chuàng )立。它原本只處理C語(yǔ)言,后續擴展可以處理C++、Objective-C、Java等其他語(yǔ)言。GCC被認為是跨平臺軟件的編譯器首選。
蘋(píng)果Mac和iOS系統
最初使用GCC編譯器,現已替代為Clang + LLVM。
為什么蘋(píng)果公司要換編譯器呢?
因為蘋(píng)果發(fā)現開(kāi)源的GCC開(kāi)發(fā)者根本使喚不動(dòng),他們不愿意專(zhuān)門(mén)為了蘋(píng)果公司的要求優(yōu)化和改進(jìn)GCC代碼,所以蘋(píng)果將編譯器后端直接替換為L(cháng)LVM(Low Level Virtual Machine,底層虛擬機),并且將讀研時(shí)(2003年)發(fā)明LLVM的天才少年克里斯·拉特納(Chris Lattner)招入麾下。克里斯進(jìn)入了蘋(píng)果之后,大幅度優(yōu)化和改進(jìn)LLVM以適應Objective-C的語(yǔ)法變革和性能要求,同時(shí)發(fā)起了CLang項目來(lái)完全替代GCC。
今天,GCC + LLVM 已經(jīng)被替換成了 Clang +LLVM。LLVM負責編譯器后端,用來(lái)處理代碼優(yōu)化和跨平臺,而Clang負責前端,只需將程序源代碼轉換成LLVM可以看得懂的IR(Intermediate Representation,中間語(yǔ)言)即可。
另外,上文提到的Swift語(yǔ)言,則是這位天才少年克里斯為蘋(píng)果公司貢獻的第三個(gè)重要作品。
安卓系統
安卓主要使用預編譯的Java語(yǔ)言開(kāi)發(fā),最初版本通過(guò)虛擬機運行,不需要編譯器,后續版本加入了JIT和AOT編譯機制(下一部分將詳細展開(kāi))。
除了上述編譯器之外,還有兩個(gè)著(zhù)名的編譯器值得一提。
Intel的ICC編譯器
ICC編譯器,全稱(chēng)Intel C++ Compiler,是Intel開(kāi)發(fā)的C/C++/Fortran編譯器套裝,適用于Linux、Microsoft和Mac OS X操作系統,廣泛應用于高性能計算、分布式計算等商業(yè)計算領(lǐng)域。
SGI等公司推出的Open64編譯器
SGI(S代表超級計算機,G代表圖形工作站,I代表具有突破性的洞察力)生產(chǎn)的超級計算機,主要應用于巨大的實(shí)驗室,采用Open64編譯器。
4. 安卓的四大命門(mén)
交待完計算機和軟件的發(fā)展歷程,終于說(shuō)到正題。
安卓系統從2008年1.0到今天的9.0,十來(lái)年間安卓系統大小版本超過(guò)15個(gè),從2016年開(kāi)始也在不斷融入了華為等手機公司發(fā)起的文件系統、人工智能學(xué)習、智能硬件調度和內存管理等底層創(chuàng )新技術(shù),安卓手機的體驗已經(jīng)今非昔比。
為什么仍然還有很多人詬病安卓手機沒(méi)有iPhone流暢?安卓系統的程序是怎樣運行的?下面展開(kāi)闡述一下安卓的四大命門(mén)。
解決安卓這四大命門(mén),也是華為方舟編譯器的使命!
第一個(gè)命門(mén)
Java的“虛擬機”
前面提到,Java為了能夠實(shí)現跨平臺操作,便借助虛擬機來(lái)調度硬件平臺資源。在虛擬機里,還需要集成翻譯器或者編譯器,來(lái)將Java的字節碼(即中間代碼)解釋成機器聽(tīng)得懂的機器語(yǔ)言,或者直接編譯成機器直接執行的010101的機器碼。
2008年,Android 1.0剛發(fā)布的時(shí)候,使用的是一個(gè)叫Dalvik的虛擬機,里面集成了一個(gè)解釋器,每次用戶(hù)在安卓手機上運行APP時(shí),就會(huì )叫醒這個(gè)解釋器,來(lái)給安卓的硬件解釋APP想要干嘛。這就相當于新聞發(fā)布會(huì ),發(fā)言人講一句自己的母語(yǔ),然后再由專(zhuān)業(yè)翻譯將其翻譯成外國記者聽(tīng)得懂的語(yǔ)言,效率非常低下,一個(gè)小時(shí)可能也問(wèn)不了幾個(gè)問(wèn)題。
谷歌意識到這個(gè)問(wèn)題嚴重拖了安卓手機的后腿,所以通過(guò)一年多的努力,在2010年中發(fā)布了2.2版本,引入了JIT(Just in Time,即時(shí)編譯)機制。JIT比較聰明,當用戶(hù)在安卓手機運行APP時(shí),會(huì )同時(shí)將用戶(hù)經(jīng)常使用的功能編譯為機器能直接執行的010101機器碼,不用每一句每一句的去翻譯。當出現不常用的功能時(shí),再把解釋器叫起來(lái)翻譯。
JIT雖然變聰明了一點(diǎn),但是每次啟動(dòng)APP都要先編譯一次,不能一勞永逸。加上Dalvik虛擬機性能比較落后,所以谷歌在2014年10月推出了Android 5.0版本,將虛擬機從Dalvik替代成ART(Android Run Time),同時(shí)把JIT的編譯器替代成AOT (Ahead of Time)。意思就是說(shuō),APP在下載后安裝到手機上時(shí)同時(shí)把能編譯的代碼先編譯成機器聽(tīng)得懂的101010。剩下不太好翻譯的代碼,就在用戶(hù)使用時(shí)再叫醒解釋器來(lái)翻譯。AOT相比JIT的好處,就是不用每次打開(kāi)APP都需要先編譯一遍。但是,壞處就是用戶(hù)安裝APP的時(shí)間有點(diǎn)長(cháng)。
越來(lái)越多的用戶(hù)吐槽為什么安裝一個(gè)APP也慢吞吞。于是,谷歌在2017年Android 7.0又做了一點(diǎn)改進(jìn),安裝時(shí)先不編譯中間代碼,而是在用戶(hù)空閑時(shí)將能夠編譯成機器碼的那部分代碼,通過(guò)AOT編譯器先靜態(tài)編譯了。如果AOT還沒(méi)來(lái)得及編譯或者不能編譯,再叫醒JIT+解釋器兩個(gè)難兄難弟來(lái)頂住。這種機制,相當于用時(shí)間換空間,既縮短了用戶(hù)安裝APP的等待時(shí)間,又將虛擬機里編譯器和解釋器能做的優(yōu)化提升到最大效率了。
很多人以為華為方舟編譯器就是Android 7.0的ART虛擬機,其實(shí)不然。

無(wú)論是編譯器還是解釋器,只是在虛擬機上打補丁。手機上的虛擬機+編譯器+解釋器本身不僅占用硬件資源,還無(wú)法最大發(fā)揮軟件運行性能。正因如此,所以絕大部分手機廠(chǎng)商只能無(wú)奈的通過(guò)簡(jiǎn)單粗暴提升安卓手機的內存和存儲空間,來(lái)彌補虛擬機的弊端。
這就是安卓的第一個(gè)命門(mén),虛擬機先天不足。
第二個(gè)命門(mén)
Java的“原罪”——額外的JNI開(kāi)銷(xiāo)
JNI,全稱(chēng)Java Native Interface(Java原生接口),用來(lái)和C/C++等代碼進(jìn)行交互。

目前95%的TOP應用都是使用Java和C/C++等多種語(yǔ)言混合開(kāi)發(fā)而成。Java和C/C++屬于兩種不同架構的語(yǔ)言,各有自己的使用規范。為了APP正常運行,它倆之間需要互通有無(wú),這個(gè)互通有無(wú)的接口就是JNI。在數據訪(fǎng)問(wèn)、函數調用、生命周期維護、異常處理等方面都需要這兩種代碼互相調用。這就意味著(zhù)手機硬件資源要分配一部分給JNI去做調度。不僅占用了硬件資源,而且這種機制本身就效率較低。
這便是額外的JNI開(kāi)銷(xiāo)。
第三個(gè)命門(mén)
代碼優(yōu)化空間有限
安卓虛擬機的編譯器受限于手機硬件和代碼優(yōu)化模板單一,代碼優(yōu)化空間有限。
編譯器包含三個(gè)部分。前端Front End,主要負責將源代碼翻譯成IR(Intermediate Representation,中間表示);中端的Optimizer主要負責代碼優(yōu)化,將前端翻譯過(guò)來(lái)的IR代碼優(yōu)化得更高效;后端Back End則將優(yōu)化后的IR編譯成101010的機器碼。

為了防止生態(tài)過(guò)于碎片化,安卓只為第三方開(kāi)放了簡(jiǎn)單的編譯代碼優(yōu)化模板,代碼優(yōu)化空間有限。
第四個(gè)命門(mén)
Java現有內存回收機制易造成間歇性卡頓
當手機內存資源不夠用的時(shí)候,安卓虛擬機就會(huì )召喚GC(Garbage Collection)封鎖公路,讓所有手機運行的Java線(xiàn)程“Stop World”,全部暫停,等待它回收內存空間,避免“交通流量超載”。這個(gè)GC機制,無(wú)法精確控制和干預,用戶(hù)也無(wú)法把它去掉,所以性能比較差的手機還存在“間歇性”卡頓。
十余年間,通過(guò)安卓系統的持續優(yōu)化,以及內存的不斷加持,安卓手機構筑了足夠流暢的用戶(hù)體驗。
但是安卓的四大命門(mén),如同達摩克利斯之劍,懸在安卓廠(chǎng)商的頭上。華為科學(xué)家和工程師們,對此持續攻關(guān)了十年,只為再造安卓。
5. 十年方舟,再造安卓
沒(méi)錯,華為為此準備了十年。
2009年,華為啟動(dòng)5G基礎技術(shù)研究的同時(shí),開(kāi)始創(chuàng )建編譯組,第一批海內外研究人員加入。
2013年,華為推出面向基站領(lǐng)域的自研編譯器HCC,并正式提出編譯器框架構想。
2014年,眾多海內外專(zhuān)家加入華為,方舟項目正式啟動(dòng)。
2016年,成立編譯器與編程語(yǔ)言實(shí)驗室。
2019年,華為方舟編譯器正式面世!

這十年,每一次攻關(guān)都蘊含著(zhù)華為軟件工程師們的傾力投入,每一個(gè)進(jìn)展都值得銘記。
2017年5月,方舟編譯器上第一個(gè)Java程序“Hello World”跑通。
2017年8月的一個(gè)凌晨,在華為的一個(gè)實(shí)驗室里,項目組已經(jīng)連續數日24小時(shí)不間斷攻關(guān),卻始終看不到success的返回信息。絕望之下,工程師把所有通信數據打印出來(lái),逐個(gè)字節排查,最終發(fā)現有一處字節的順序不一致。糾正后,華為方舟跑通了第一個(gè)安卓后臺服務(wù)DiskStatus,這標志著(zhù)對安卓的換心手術(shù)進(jìn)入了實(shí)操階段。
2018年春節前一周,方舟編譯器跑通安卓系統所有后臺服務(wù),并成功移植到手機。當晚,所有人聚集在實(shí)驗室的機房中,等待首個(gè)開(kāi)機畫(huà)面加載成功的神圣時(shí)刻。秒針滴答,如同過(guò)了一個(gè)世紀那么久,屏幕終于點(diǎn)亮。
歡呼,擁抱,一蹦三尺高,項目組成員們到底沒(méi)忍住,留下了激動(dòng)的淚水。
接下來(lái),項目組在除夕前夜啟動(dòng)了方舟編譯手機的Beta測試。大年初一清晨,總架構師發(fā)來(lái)了第一條經(jīng)編譯器編譯的運行程序發(fā)出來(lái)的拜年消息:
春節快樂(lè ),方舟大吉!
當P30發(fā)布會(huì )上“方舟”甫一出現,就在中國軟件行業(yè)“炸”了鍋。無(wú)數軟件從業(yè)者從一開(kāi)始的質(zhì)疑,到弄清方舟真相后的驚嘆……這些都是對華為軟件工程師們十年如一日、一點(diǎn)一滴“啃硬骨頭”的致敬!
實(shí)際上,方舟已經(jīng)不是傳統意義上從高級語(yǔ)言到機器碼的“萬(wàn)能翻譯”,更是一個(gè)編譯運行系統。
一方面,方舟編譯器首次在Java領(lǐng)域將虛擬機干掉了,也是軟件史上首次將Java/C/C++等混合代碼一次編譯成機器碼直接在手機上運行,徹底告別Java的JNI額外開(kāi)銷(xiāo),也徹底告別了虛擬機GC內存回收帶來(lái)的應用進(jìn)程掉線(xiàn),使操作流暢度大幅提升。如果說(shuō)目前最新的安卓系統是和諧號動(dòng)車(chē),那么經(jīng)方舟編譯的安卓系統便是高鐵,是“復興號”。
華為手機直接通過(guò)方舟編譯器替換了Android system-server的所有后臺服務(wù),這一項就已經(jīng)足夠讓華為EMUI比其他安卓系統更快一步。根據華為官方測試,方舟編譯器提升手機系統操作流暢度高達24%,系統響應性能提升44%。入手P30系列的用戶(hù),應該已經(jīng)體驗到了。
另一方面,方舟編譯器用空間換性能,直接將編譯器的代碼優(yōu)化搬到了開(kāi)發(fā)者環(huán)境,不再被手機端的硬件資源所限制,為代碼優(yōu)化提供了無(wú)限可能。
此外,經(jīng)測試,新浪微博極速版APP經(jīng)方舟編譯后,操作流暢度提升高達60%。
解決安卓的四大命門(mén),出于安卓,勝于安卓,超越iOS,并且全面兼容安卓,這就是華為方舟編譯器的使命!
6. 生來(lái)就是要干掉虛擬機
方舟編譯器從立項開(kāi)始,就是要徹底干掉虛擬機。這在歷史上,是從來(lái)沒(méi)有人做過(guò)的。
SUN公司當初發(fā)明Java語(yǔ)言,就是借助虛擬機的這個(gè)“萬(wàn)能中轉站”,屏蔽掉各種硬件的差異,方便同一個(gè)代碼在多個(gè)平臺運行,所以Java是目前最流行的高級編程語(yǔ)言之一。這么多年,從來(lái)沒(méi)有人能夠干掉虛擬機,說(shuō)明難度非常之大。
那么方舟編譯器,是如何完全干掉虛擬機的呢?
最關(guān)鍵的就是要能夠將Java代碼直接編譯成010101的機器碼。
這種設想在理論是可行的,但是從現實(shí)來(lái)講太難了。歷史上有過(guò)一些嘗試,比如現在大行其道的安卓ART虛擬機。這些嘗試能夠提前翻譯Java語(yǔ)言里很多的靜態(tài)語(yǔ)義,但是多數的動(dòng)態(tài)語(yǔ)義,仍然搞不定,還得交給虛擬機。
所謂靜態(tài)語(yǔ)義,我們可以理解為確定的語(yǔ)言和意思,比如“我是張三”。而動(dòng)態(tài)語(yǔ)義,則需要結合上下文去理解,比如“能穿多少就穿多少”,到底穿多還是穿少,要看是冬天還是夏天了。例如大家熟悉的微博、京東等APP的開(kāi)屏廣告就需要用到動(dòng)態(tài)語(yǔ)義。像編譯靜態(tài)語(yǔ)義一樣去編譯動(dòng)態(tài)語(yǔ)義,很多知乎大神認為根本就不可能。

為了這個(gè)目標,華為軟件工程師們對自己苛求再苛求,這里涉及到大量的細節,從對象模型的設計,到每一個(gè)bit的用途、每一個(gè)對象的元數據metadata(描述數據的數據)每一個(gè)編譯優(yōu)化的設計,都經(jīng)過(guò)了無(wú)數次的激烈討論和推倒重來(lái)。
最終,方舟編譯器通過(guò)編譯階段和運行階段的雙向加持,將靜態(tài)編譯動(dòng)態(tài)語(yǔ)義最大的兩大難點(diǎn)一一解決:一是設計數據模型,二是如何在運行時(shí)高效獲得動(dòng)態(tài)信息。方舟編譯器團隊基本遍歷了Java的動(dòng)態(tài)語(yǔ)義,進(jìn)行了大規模的數據建模。同時(shí),大大提高了編譯時(shí)動(dòng)態(tài)語(yǔ)義分析的精度,特別是涉及跨語(yǔ)言調用時(shí);另外,華為設計了一套具有核心專(zhuān)利的動(dòng)態(tài)語(yǔ)義匹配機制,有效降低了運行時(shí)動(dòng)態(tài)語(yǔ)義的開(kāi)銷(xiāo)。
正是因為這兩大難點(diǎn)的突破,讓方舟編譯器能夠將Java代碼編譯成機器能直接執行的語(yǔ)言。經(jīng)過(guò)華為方舟編譯器的APP,再也不需要在手機上編譯了,徹底告別了虛擬機,從而帶來(lái)了媲美甚至超越iOS的安卓體驗。
7. 代碼“萬(wàn)國通”
95%的Top應用都是Java/C/C++等混合語(yǔ)言編寫(xiě)而成。方舟編譯器的第二個(gè)使命,就是干掉混合語(yǔ)言互相調用帶來(lái)的JNI開(kāi)銷(xiāo)。
華為方舟編譯器團隊基于多個(gè)編程語(yǔ)言的深刻理解和大量研發(fā)積累,將混合語(yǔ)言破天荒實(shí)現了統一的中間表示IR,這就相當于同一個(gè)人能夠理解全世界的語(yǔ)言,所以我們把這個(gè)革命性突破叫做,代碼“萬(wàn)國通”。
那么方舟編譯器是如何使用統一的IR來(lái)表示各種語(yǔ)言呢?
IR是用來(lái)表示代碼的數據結構,它是編譯器的各模塊以及相關(guān)工具之間用來(lái)傳遞信息的“協(xié)議和通用語(yǔ)言”,也是程序變換和編譯優(yōu)化各種算法的承載體。它是編譯器的“大腦”,直接決定了編譯器的最終效果。它的難度是最高的。
華為方舟編譯器團隊對IR進(jìn)行了長(cháng)達五年的精雕細琢,逐漸摸索出“大腦”里每一條神經(jīng)、每一個(gè)神經(jīng)元的信號規律,并在此基礎上發(fā)明了一套核心專(zhuān)利,使得不同語(yǔ)言代碼在開(kāi)發(fā)者環(huán)境中能夠統一編譯成同一套可直接執行的機器碼,從而徹底消除混合語(yǔ)言互相調用的開(kāi)銷(xiāo)。
8. 給代碼裝上飛機發(fā)動(dòng)機
除了IR,編譯器還有一個(gè)非常重要的價(jià)值,就是代碼優(yōu)化。
華為方舟編譯器,直接將代碼優(yōu)化從手機環(huán)節搬到了開(kāi)發(fā)者環(huán)境,未來(lái)還可能搬到云端。利用開(kāi)發(fā)者環(huán)境更強大的算力,可以實(shí)現更先進(jìn)和精細的優(yōu)化算法,來(lái)達到更強大的優(yōu)化效果,在很多特定場(chǎng)景代碼優(yōu)化的提升甚至是顛覆性的。

這相當于給APP在方舟里裝上飛機發(fā)動(dòng)機,讓你的APP運行如飛!
值得一提的是,開(kāi)發(fā)者使用方舟編譯器,并不需要改變原來(lái)的編碼習慣。開(kāi)發(fā)者可以自行開(kāi)發(fā)代碼優(yōu)化算法,也可以?xún)H通過(guò)方舟編譯器預置的算法進(jìn)行代碼優(yōu)化。未來(lái),華為還將提供代碼調優(yōu)工具,開(kāi)發(fā)者可以選擇根據工具的優(yōu)化建議來(lái)調整代碼,和方舟編譯器配合獲得更優(yōu)的執行效果。
可以想象,未來(lái)廣大APP開(kāi)發(fā)者使用方舟編譯器后,消費者們的體驗將達到一個(gè)前所未有的高度。這對于整個(gè)安卓生態(tài),都是一件前所未有的幸事!
9. Stop World,安卓卡頓再見(jiàn)
方舟的第四個(gè)使命,就是解決安卓虛擬機GC內存回收帶來(lái)的“Stop World”。
目前安卓手機內存資源不夠用的時(shí)候,GC直接叫停所有應用,所以偶爾會(huì )遭遇莫名卡頓。

方舟編譯器采用了引用計數法(RC,Reference Counting)來(lái)進(jìn)行內存的實(shí)時(shí)回收,并且配合使用了專(zhuān)門(mén)的消除環(huán)算法(消除對象互相引用帶來(lái)的無(wú)法回收問(wèn)題),來(lái)避免GC集中式回收帶來(lái)的系統卡頓。相比GC,方舟的內存回收是實(shí)時(shí)的而非集中式的,且不需要暫停應用進(jìn)程,這樣便大大消除了卡頓。
如果把內存回收比作成打掃房間,那么GC的策略是專(zhuān)門(mén)有一個(gè)衛生員,看房間里垃圾太多了,就把所有人請出去,打掃完了再讓大家回來(lái)。而方舟的RC則是每個(gè)人收拾自己的垃圾,用完就清理,保持清潔的同時(shí)不影響人的正常活動(dòng)。
軟件有一個(gè)大家很熟悉的死循環(huán),就是電腦被一個(gè)無(wú)限循環(huán)的運行程序把計算機資源占光。
這種“死循環(huán)”在軟件中叫“環(huán)引用”。為了從機制避免手機內存被環(huán)引用“吃掉”,方舟編譯器引入annotation的“告警”標示,對基礎類(lèi)的環(huán)進(jìn)行標注。當然,Java程序員也可以對業(yè)務(wù)代碼中的環(huán)進(jìn)行標注。經(jīng)過(guò)豐富的實(shí)踐驗證,方舟這種機制可減少大部分程序中環(huán)的出現。
另外一方面,方舟編譯器在運行狀態(tài)下引入了高效的環(huán)回收機制,允許有選擇的智能回收某個(gè)APP的內存占用,這對傳統的環(huán)回收算法是一個(gè)非常棒的改進(jìn)。
Stop World,安卓卡頓,再見(jiàn)!
正是因為方舟做到混合語(yǔ)言的統一中間表示和完全靜態(tài)編譯,它干掉了虛擬機,消除了JNI開(kāi)銷(xiāo),告別了GC內存回收的“間歇性”卡頓,以及其他很多開(kāi)銷(xiāo)。同時(shí),為開(kāi)發(fā)者進(jìn)行代碼優(yōu)化提供了一個(gè)更廣闊的舞臺。
華為很快將全面開(kāi)源方舟編譯器,屆時(shí)開(kāi)發(fā)者們可以使用方舟編譯器作為開(kāi)發(fā)工具,為移動(dòng)應用生態(tài)和體驗打開(kāi)一扇全新的大門(mén)。
科技的進(jìn)步,離不開(kāi)全球無(wú)數科學(xué)家和工程師的奉獻。產(chǎn)業(yè)的繁榮,開(kāi)放是唯一出路!
最后,以L(fǎng)inux 的創(chuàng )始人Linus Torvalds的名言結尾!
Talk is cheap. Show me the code!
空談?wù)`國,實(shí)干興邦!
本文由菊廠(chǎng)搞機MO編輯部出品,文字超1萬(wàn),查閱的資料多達上百萬(wàn)文字,并且與華為方舟編譯器的專(zhuān)家做過(guò)深度訪(fǎng)談。文章高度概括了波瀾壯闊的軟件產(chǎn)業(yè)發(fā)展史,解析了華為在編譯器和手機系統方面做的多年準備。
本文由菊廠(chǎng)搞機MO編輯部出品,文字超1萬(wàn),查閱的資料多達上百萬(wàn)文字,并且與華為方舟編譯器的專(zhuān)家做過(guò)深度訪(fǎng)談。文章高度概括了波瀾壯闊的軟件產(chǎn)業(yè)發(fā)展史,解析了華為在編譯器和手機系統方面做的多年準備。