自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

華為方舟編譯器做了些什么,讓安卓有了“絲滑”的感覺 ?

開發(fā) 開發(fā)工具
我們都知道,Java的字節(jié)碼需要運(yùn)行在Java虛擬機(jī)(JVM)上。JVM最重要的功能有兩個(gè):執(zhí)行字節(jié)碼和內(nèi)存管理;我們分頭來說說。

 [[265347]]

敲黑板,先來講幾個(gè)術(shù)語:

1. JIT

全稱是Just-in-time,即時(shí)編譯;當(dāng)Java字節(jié)碼運(yùn)行在JVM上的時(shí)候,JVM實(shí)時(shí)得把字節(jié)碼編譯成機(jī)器碼就叫JIT。

2. AOT

全稱是Ahead-of-time,預(yù)先編譯;與JIT對(duì)應(yīng),你JIT不是實(shí)時(shí)的嗎?那我先提前編譯好,就是AOT。

3. IR

全程是Intermediate representation,即中間表示。中間表示是一個(gè)從原始表示到目標(biāo)表示之間的中間層。

現(xiàn)代編譯器分為前端和后端,前后端的分界線就是IR。

現(xiàn)代編譯器的大致流程:詞法分析->語法分析->語義分析->IR->優(yōu)化->生成目標(biāo)代碼。

針對(duì)華為給出的方舟編譯器的講解,我們來看看方舟到底做了什么,以及推測(cè)一下方舟可能做了什么,或者方舟可以做什么。

1. 無需虛擬機(jī)運(yùn)行

我們都知道,Java的字節(jié)碼需要運(yùn)行在Java虛擬機(jī)(JVM)上。JVM最重要的功能有兩個(gè):執(zhí)行字節(jié)碼和內(nèi)存管理;我們分頭來說說。

執(zhí)行字節(jié)碼

當(dāng)JVM運(yùn)行字節(jié)碼的時(shí)候,會(huì)讀取一條一條的指令,然后把指令翻譯成當(dāng)前機(jī)器的機(jī)器碼并執(zhí)行該操作,比如把當(dāng)前棧上的兩個(gè)數(shù)加起來然后再次壓棧等等,這種方式叫做解釋執(zhí)行。

當(dāng)JVM發(fā)現(xiàn)某一些指令經(jīng)常會(huì)被執(zhí)行到,每次翻譯一遍會(huì)導(dǎo)致運(yùn)行效率降低,于是JVM就把這些指令直接編譯成當(dāng)前機(jī)器的機(jī)器碼,下次就直接執(zhí)行機(jī)器碼,不需要逐句翻譯一遍,這就是JIT。

內(nèi)存管理

寫C代碼的同學(xué)們,想要使用內(nèi)存的時(shí)候,需要調(diào)用malloc函數(shù)動(dòng)態(tài)申請(qǐng)一段內(nèi)存,不再使用這段內(nèi)存的時(shí)候,需要調(diào)用free函數(shù)進(jìn)行內(nèi)存釋放,如果不釋放,后果很嚴(yán)重。

而寫Java代碼的同學(xué)們就沒有這個(gè)困惑,因?yàn)檫@件事被JVM承包了下來。JVM在執(zhí)行字節(jié)碼的過程中,會(huì)調(diào)用gc(garbage collection),gc幫我們釋放不需要的內(nèi)存。

方舟是怎么做的?

清楚了以上過程,我們就明白方舟編譯器是怎么做的了。

既然JVM可以在運(yùn)行過程中可以把字節(jié)碼編譯為機(jī)器碼(JIT),那么為什么不能在運(yùn)行字節(jié)碼之前把字節(jié)碼編譯成機(jī)器碼呢?沒錯(cuò),方舟就是這么做的,我們稱之為AOT。

JVM的兩大功能之一執(zhí)行字節(jié)碼就不需要了,那還有一個(gè)內(nèi)存管理的功能怎么辦呢?這個(gè)也好辦,華為可以提供一個(gè)庫,這個(gè)庫實(shí)現(xiàn)gc所有的功能,我們稱這個(gè)庫為runtime。

以前我們使用JVM來運(yùn)行一段字節(jié)碼,現(xiàn)在這個(gè)流程變了,變成先把字節(jié)碼(或者源程序)編譯成機(jī)器碼,然后帶上runtime,直接運(yùn)行在操作系統(tǒng)上,就不再需要VM了。

VM是不需要了,runtime是必不可少的,這個(gè)runtime需要處理包括但不限于以下幾件事:創(chuàng)建對(duì)象,gc,函數(shù)調(diào)用,異常處理,鎖,同步,多線程,反射。

都已經(jīng)帶上了這么多功能,那再帶上一個(gè)解釋器吧,多一個(gè)不嫌多。這些東西好像有些耳熟啊,好像安卓的ART也是這樣的?我猜是的,由于Java語言本身和Java的運(yùn)行時(shí)庫等等一些歷史原因,想推翻重來把這些東西都去掉,復(fù)雜度是很高的;所以安卓的爸爸谷歌也是在這些基礎(chǔ)上進(jìn)行修修補(bǔ)補(bǔ)。

當(dāng)然,華為也可以選擇不支持Java中一些動(dòng)態(tài)的特性比如反射等功能,那么這個(gè)runtime是有可能簡(jiǎn)化的。到底方舟編譯器和安卓已有的ART有什么不同,我們拭目以待。

2. 多語言聯(lián)合優(yōu)化編譯器

這個(gè)很神奇對(duì)吧,C語言竟然可以和Java語言聯(lián)合在一起編譯。

我們知道C語言的代碼編譯過后是二進(jìn)制文件,Java語言的代碼編譯過后是字節(jié)碼;其實(shí)現(xiàn)代編譯器在編譯過程中有很多層中間表示,如果把源代碼層看做***層次,目標(biāo)語言看成***層次,編譯過程中是逐層下降的,***下降到目標(biāo)層,和我們下樓梯是一樣一樣的,并不是自由落體對(duì)不對(duì)。

比如源代碼經(jīng)過編譯器前端之后變成抽象語法樹(AST),抽象語法樹又可以轉(zhuǎn)變?yōu)榱硪环N更低層級(jí)的中間表示(IR),然后從IR再到目標(biāo)層。

所以方舟可以定義一個(gè)中間表示(IR),把C語言和Java語言都先編譯到這個(gè)中間表示層,然后在中間表示層做一系列的優(yōu)化或者分析,再從中間表示層編譯到機(jī)器碼,這樣就實(shí)現(xiàn)了多語言聯(lián)合編譯。

是不是把不同的語言編譯到同一種IR上就萬事大吉了呢?不是這樣的!

方舟為什么要把多個(gè)語言放在一起編譯?是好玩嗎?當(dāng)然不是!多個(gè)語言聯(lián)合編譯至少有以下幾點(diǎn)好處:

減小跨語言調(diào)用開銷

不同的語言之間,類型系統(tǒng)、調(diào)用規(guī)范、數(shù)據(jù)布局等等都不同,所以不同語言相互調(diào)用時(shí)有一些額外的開銷。

我們知道Java調(diào)用C的接口規(guī)范叫做JNI,JNI幫助我們跨越語言的鴻溝,實(shí)現(xiàn)Java和C相互之間的調(diào)用。AOT在跨越語言鴻溝方面有一些好處,不同語言用同一個(gè)IR表示,runtime也是自己定制的,這不就是前店后廠嘛;

這樣就有機(jī)會(huì)抹平不同語言之間的差異,比如可以讓Java對(duì)象的數(shù)據(jù)布局和C中的對(duì)象數(shù)據(jù)布局保持一致,比如可以讓C來兼容Java的類型系統(tǒng)(Java語言可以看做C++語言的一個(gè)子集)等等;提前抹平差異,使不同的東西保持一致,就不必在運(yùn)行程序的時(shí)候再次進(jìn)行轉(zhuǎn)換,可以減小開銷。

跨語言優(yōu)化

一般情況下,不同的語言是分開編譯的。而方舟編譯器將不同的語言編譯到同樣的IR,便于將不同語言的代碼聯(lián)合起來進(jìn)行全局優(yōu)化,比如常量傳播,函數(shù)內(nèi)聯(lián)等等。

當(dāng)所有的代碼都在同一IR上之后,還可以針對(duì)Java語言的特性做一些特定的靜態(tài)分析,通過分析結(jié)果進(jìn)行特定優(yōu)化,比如可以針對(duì)不同種類的函數(shù)調(diào)用做de-virtualization等等。

什么是de-virtulization?簡(jiǎn)單來講就是一些函數(shù)調(diào)用是通過類似于函數(shù)指針調(diào)用的方式間接調(diào)用,分析清楚這些間接調(diào)用可以把一些間接調(diào)用改成直接調(diào)用,而且是跨語言的直接調(diào)用,神奇吧!

3. 更高效的內(nèi)存回收機(jī)制

內(nèi)存回收是一個(gè)大問題,安卓應(yīng)用卡頓部分原因就在內(nèi)存回收。

前面提到,Java的內(nèi)存回收工作被JVM接管了,寫Java代碼的同學(xué)并不需要手動(dòng)進(jìn)行內(nèi)存回收,JVM會(huì)在“適當(dāng)”的時(shí)候進(jìn)行內(nèi)存回收。

這個(gè)“適當(dāng)”的時(shí)候通常是沒有辦法的時(shí)候,內(nèi)存耗盡的時(shí)候;好比我有一張干凈的桌子(堆內(nèi)存),我們?cè)谧雷由厦鏀[放了一些東西(消耗內(nèi)存),當(dāng)沒有地方可以擺放新東西的時(shí)候,那就需要媽媽來幫忙收拾桌面了(內(nèi)存回收)。

JVM中的GC如何判斷哪些內(nèi)存是需要的哪些內(nèi)存是不需要的呢?這里面有個(gè)叫可達(dá)性分析的技術(shù)來幫我們判斷哪些內(nèi)存可以回收。

可達(dá)性分析的大致思想是,JVM運(yùn)行過程中,創(chuàng)建了很多對(duì)象,這些對(duì)象之間有復(fù)雜的依賴關(guān)系,JVM先確定一些對(duì)象是根對(duì)象,從根對(duì)象出發(fā),把所有直接依賴的對(duì)象和間接依賴的對(duì)象都標(biāo)記出來,沒有被依賴到的對(duì)象就不需要使用了,可以進(jìn)行回收。

當(dāng)有一段程序,在循環(huán)中大量創(chuàng)建新的對(duì)象,會(huì)造成內(nèi)存快速耗盡,然后觸發(fā)gc進(jìn)行內(nèi)存回收;頻繁觸發(fā)gc回收大量?jī)?nèi)存,這種現(xiàn)象叫做內(nèi)存抖動(dòng),是造成安卓應(yīng)用卡頓的一個(gè)很重要的原因。

寫iOS應(yīng)用的同學(xué)說我也沒有管理內(nèi)存,但是我寫的應(yīng)用就如絲般順滑。是的,iOS應(yīng)用較少發(fā)生內(nèi)存抖動(dòng)現(xiàn)象,使用了一種叫做引用計(jì)數(shù)的方法,其實(shí)這也是可達(dá)性分析技術(shù)里面的一種,Objective-C中稱之為ARC。

引用計(jì)數(shù)是這樣一種算法,每個(gè)對(duì)象都有一個(gè)計(jì)數(shù)器,當(dāng)創(chuàng)建對(duì)象時(shí)候或者有其它的對(duì)象引用這個(gè)對(duì)象的時(shí)候,計(jì)數(shù)器數(shù)字也加1;當(dāng)別的對(duì)象不再引用它時(shí),計(jì)數(shù)器數(shù)字減1。

當(dāng)計(jì)數(shù)器的數(shù)字回到0時(shí),就將該對(duì)象回收。

還是剛才那個(gè)循環(huán),在循環(huán)中創(chuàng)建大量對(duì)象,只要本次循環(huán)結(jié)束,就可以回收剛剛創(chuàng)建的對(duì)象,不會(huì)造成內(nèi)存抖動(dòng)。

對(duì)引用計(jì)數(shù)進(jìn)行加1的動(dòng)作好理解,這是用戶自己寫的代碼,用戶的代碼中會(huì)寫清楚什么時(shí)候創(chuàng)建對(duì)象,什么時(shí)候有了新的引用;對(duì)引用計(jì)數(shù)進(jìn)行減1是誰來做的呢?

這個(gè)時(shí)候編譯器就派上用場(chǎng)了,編譯器可以分析對(duì)象的生命周期,在合適的地方插入這個(gè)對(duì)象減1的代碼,這樣在程序運(yùn)行的時(shí)候引用計(jì)數(shù)就會(huì)加加減減。

方舟編譯器的宣傳材料中提到“隨用隨回收”,那么應(yīng)該是使用了引用計(jì)數(shù)類似的技術(shù),來減小內(nèi)存抖動(dòng)。當(dāng)然,由于Java語言的問題,引用計(jì)數(shù)并不能解決所有問題,即使使用了引用計(jì)數(shù),也需要gc來幫助回收內(nèi)存。宣傳材料中“回收時(shí)無需暫停應(yīng)用”,應(yīng)該是實(shí)現(xiàn)或者改進(jìn)了Concurrent GC,來盡可能減小應(yīng)用的停頓。

通過引用計(jì)數(shù)和改進(jìn)GC,可以優(yōu)化內(nèi)存回收,減少內(nèi)存回收的次數(shù)和減少暫停時(shí)間;既然有了統(tǒng)一的IR是不是可以天馬行空一下,除了以上的東西可不可以做更多的一些優(yōu)化呢?

前面提到引用計(jì)數(shù)可以解決局部變量用完馬上回收的問題,而全局變量就搞不定了。那么方舟編譯器有可能可以在這方面做一些文章,比如可以通過分析把一部分全局變量變成局部變量;再比如可以分析全局變量的生存周期,對(duì)全局變量也進(jìn)行引用計(jì)數(shù)??傊?,立即釋放更多不需要使用的內(nèi)存,就可以減少GC,減少卡頓。

好了,胡言亂語完了,我們還是等方舟編譯器開源了,然后再一探究竟吧。

【本文為51CTO專欄作者“劉欣”的原創(chuàng)稿件,轉(zhuǎn)載請(qǐng)通過作者微信公眾號(hào)coderising獲取授權(quán)】

 

戳這里,看該作者更多好文

 

責(zé)任編輯:武曉燕 來源: 51CTO專欄
相關(guān)推薦

2019-08-06 08:20:07

編譯器工具開發(fā)者

2019-06-14 08:35:14

華為禁令開發(fā)

2019-04-26 06:20:32

安卓華為編譯

2019-04-12 09:10:25

開源技術(shù) 軟件

2019-09-02 09:59:48

華為方舟編譯器開源

2019-09-10 08:30:55

華為開發(fā)者開源

2019-06-26 09:32:28

華為禁令開發(fā)

2019-09-09 09:12:43

2019-08-09 17:33:42

華為鴻蒙開發(fā)

2019-09-02 00:06:36

華為開發(fā)者開源

2025-03-03 12:00:00

JavaScriptfor 循環(huán)語言

2020-07-22 15:15:28

Vue前端代碼

2012-04-05 09:13:17

C代碼

2022-08-02 08:11:41

監(jiān)控埋點(diǎn)埋點(diǎn)方式插樁

2021-07-14 13:46:28

KubeVela阿里云容器

2025-03-10 08:44:17

2021-11-17 08:16:03

內(nèi)存控制Go

2022-08-28 10:08:53

前端代碼前端

2023-03-15 15:54:36

Java代碼

2020-08-26 09:05:03

函數(shù)編譯詞法
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)