国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

javascript引擎——V8

luoyibu / 2282人閱讀

摘要:類將源代碼解釋并構(gòu)建成抽象語法樹,使用類來創(chuàng)建它們,并使用類來分配內(nèi)存。類抽象語法樹的訪問者類,主要用來遍歷抽象語法樹。在該函數(shù)中,先使用類來生成抽象語法樹再使用類來生成本地代碼。

通過上一篇文章,我們知道了JavaScript引擎是執(zhí)行JavaScript代碼的程序或解釋器,了解了JavaScript引擎的基本工作原理。我們經(jīng)常聽說的JavaScript引擎就是V8引擎,這篇文章我們就來認(rèn)識一下V8引擎,我們先來看一下除了V8引擎,還有哪些JS引擎:

V8 開源
由Google開發(fā),用C++編寫。V8 最早被開發(fā)用以嵌入到 Google 的開源瀏覽器 Chrome 中,但是 V8 是一個可以獨立的模塊,完全可以嵌入您自己的應(yīng)用,著名的 Node.js( 一個異步的服務(wù)器框架,可以在服務(wù)端使用 JavaScript 寫出高效的網(wǎng)絡(luò)服務(wù)器 ) 就是基于 V8 引擎的。

Rhino開源
?由Mozilla基金所管理,完全用Java開發(fā)

JavaScriptCore 開源
由蘋果公司為Safari開發(fā)

SpiderMonkey
第一個JavaScript引擎,最早用在Netscape Navigator上,現(xiàn)在用在Firefox上

KJS
KDE的引擎,最初由Harri Porten為KDE項目的Konqueror網(wǎng)頁瀏覽器所開發(fā)

Chakra(JScript9)
?Internet Explorer 瀏覽器

Chakra(JavaScript)

Microsoft Edge

Nashorn
OpenJDK開源項目的一部分,用的是Oracle Java語言和工具組

JerryScript
用于物聯(lián)網(wǎng)的輕量級引擎

在這些項目中,V8引擎因其在性能上的突出表現(xiàn),倍受大家的關(guān)注,所以我們也以介紹V8引擎為主。V8是Google開源的高性能JavaScript引擎,用C++編寫。它用于谷歌瀏覽器,谷歌的開源瀏覽器,以及Node.js等等。

速度是V8追求的主要設(shè)計目標(biāo)之一,在一些性能測試中,V8比IE的JScript,F(xiàn)irefox中的SpiderMonkey以及Safari中的JavaScriptCore要快上數(shù)倍。相比其他的JavaScript引擎轉(zhuǎn)化成字節(jié)碼或解釋執(zhí)行,V8將其編譯成本地代碼,并且使用了如隱類型,內(nèi)聯(lián)緩存等方法來提高性能。

http://kourge.net/node/122

V8按照ECMA-262第5版中的規(guī)定實施ECMAScript,支持眾多操作系統(tǒng),如windows、linux、android等,也支持其他硬件架構(gòu),如IA32,X64,ARM等,具有很好的可移植和跨平臺特性。

V8的工作過程

V8工作的整個過程與Java有些類似,大致分成兩個階段:第一是編譯,第二是運行。與C++直接編譯成本地代碼不同的是,V8只有在函數(shù)調(diào)用時才會編譯成本地代碼,這樣就提高了響應(yīng)時間減少了時間開銷。

圖片來源《WebKit技術(shù)內(nèi)幕》

在V8引擎中,源代碼先通過解析器轉(zhuǎn)變成抽象語法樹,這點同JavaScriptCore引擎一樣,不同于JavaScriptCore引擎,V8引擎中并不將抽象語法樹轉(zhuǎn)變成字節(jié)碼或者其他中間表示,而是通過JIT全代碼生成器(full code generator)從抽象語法樹直接生成本地代碼,這樣做可以減少抽象語法樹到字節(jié)碼的轉(zhuǎn)換時間,提高代碼的執(zhí)行速度,但也是因為缺少了轉(zhuǎn)換為字節(jié)碼這一中間過程,也就減少了優(yōu)化中間代碼的機會。

下面來看一下V8引擎編譯JavaScript生成本地代碼使用了哪些主要類:

Script類:表示是JavaScript代碼,既包含源代碼,又包含編譯之后生成的本地代碼,所以它既是編譯入口,又是運行入口

Compiler類:編譯器類,輔助Script類來編譯生成代碼,它主要起一個協(xié)調(diào)者的作用,會調(diào)用解釋器(Parser)來生成抽象語法樹和全代碼生成器,來為抽象 語法樹生成本地代碼。

Parser類:將源代碼解釋并構(gòu)建成抽象語法樹,使用AstNode類來創(chuàng)建它們,并使用Zone類來分配內(nèi)存。

AstNode類:抽象語法樹節(jié)點類,是其他所有節(jié)點的基類,它包含非常多的子類,后面會針對不同的子類生成不同的本地代碼。

AstVisitor類:抽象語法樹的訪問者類,主要用來遍歷抽象語法樹。

FullCodeGenerator:AstVisitor類的子類,通過遍歷抽象語法樹來為JavaScrit生成本地代碼。

圖片來源《WebKit技術(shù)內(nèi)幕》

JavaScript代碼編譯的過程大致為:Script類調(diào)用Compiler類的Compile函數(shù)生成本地代碼。在該函數(shù)中,先使用Parser類來生成抽象語法樹;再使用FullCodeGenerator類來生成本地代碼。

圖片來源《WebKit技術(shù)內(nèi)幕》

本地代碼與具體的硬件平臺密切相關(guān),F(xiàn)ullCodeGenerator使用多個后端來生成與平臺相匹配的本地匯編代碼。由于FullCodeGenerator通過遍歷AST來為每個節(jié)點生成相應(yīng)的匯編代碼,缺失了全局視圖,節(jié)點之間的優(yōu)化也就無從談起。

JavaScript代碼編譯之前需要構(gòu)建一個運行環(huán)境,所以JavaScript代碼編譯之前,V8引擎會構(gòu)建眾多對象并加載一些內(nèi)置的庫(如Math庫)。再次強調(diào)一下,在JavaScript源碼中,并非所有的函數(shù)都被編譯生成本地代碼,而是延時編譯,在調(diào)用時才會編譯。

由于V8缺少生成字節(jié)碼(中間表示)這一環(huán)節(jié),缺少必要的優(yōu)化,為了性能上的考慮,V8會在生成本地代碼后,使用數(shù)據(jù)分析器(Profiler)采集一些信息,然后根據(jù)這些信息對本地代碼進行優(yōu)化,生成更高效率的本地代碼,這是一個逐步改進的過程。同時,當(dāng)發(fā)現(xiàn)優(yōu)化后的代碼性能并沒有提高甚至還有所降低時,V8將退回到原來的代碼。這些都是在運行階段用涉及到的技術(shù)。

現(xiàn)在我們來看一下運行階段使用到的類:

Script: 表示是JavaScript代碼,既包含源代碼,又包含編譯之后生成的本地代碼,所以它既是編譯入口,又是運行入口

Execution: 運行代碼的輔助類,包含一些重要的函數(shù),例如call,它輔助進入和執(zhí)行Script中的本地代碼

JSFunction: 需要執(zhí)行的JavaScript函數(shù)表示類

Runtime:運行這些本地代碼的輔助類,它的功能主要是提供運行時各種各樣的輔助函數(shù),包括但是不限于屬性訪問、類型轉(zhuǎn)換、編譯、算數(shù)、位操作、比較、正則表達(dá)式等

Heap:運行本地代碼需要使用內(nèi)存堆

MarkCompactCollector:垃圾回收機制的主要實現(xiàn)類,用來標(biāo)記(Mark)、清除(Sweep)和整理(Compact)等基本的垃圾回收過程

SweeperThread:負(fù)責(zé)垃圾回收的線程


圖片來源《WebKit技術(shù)內(nèi)幕》

首先,當(dāng)某個JavaScript函數(shù)被調(diào)用時,使用編譯階段的類和操作編譯生成本地代碼。具體的工作方式是V8查找函數(shù)是否已經(jīng)生成本地代碼,如果已經(jīng)生成,那么直接使用這個函數(shù)。否則,V8引擎會觸發(fā)生成本地代碼,這樣的工作方式可以節(jié)約時間,減少去處理那些使用不到的代碼的時間。其次,執(zhí)行編譯后的代碼為JavaScript構(gòu)建JS對象,這需要Runtime類來輔助創(chuàng)建對象,并需要從Heap類分配內(nèi)容。再次,借助Runtime類中的輔助函數(shù)來完成一些功能,如屬性訪問,類型轉(zhuǎn)換等。最后,將不用的空間進行標(biāo)記清除和垃圾回收。


圖片來源《WebKit技術(shù)內(nèi)幕》

V8特性簡介 一. 優(yōu)化回滾

FullCodeGenerator編譯器基于抽象語法樹直接生成本地代碼,沒有中間表示層,所以很多時候沒有經(jīng)過很好的優(yōu)化。JavaScript引擎性能之爭非常激烈,沒有經(jīng)過優(yōu)化的代碼導(dǎo)致該引擎在性能上同有特別大的突破,而其他引擎都在進度,有鑒于此,在2010年,V8引入了新的編譯器,這就是Crankshaft編譯器,它主要針對那些熱點函數(shù)進行優(yōu)化。該編譯器基于JavaScript源代碼開始分析,而不是本地代碼,同時構(gòu)建Hydtogen圖并基于此來進行優(yōu)化分析。

FullCodeGenerator是一個簡單且快的編譯器,生成未優(yōu)化的本地代碼,運行起來很慢;Crankshaft是一個相對慢的編譯器,生成高度優(yōu)化的代碼。由FullCodeGenerator生成的未優(yōu)化代碼Crankshaft優(yōu)化代碼替換,傳送門。

Crankshaft編譯器為了性能考慮,通常會做出比較樂觀和大膽的預(yù)測,那就是編譯器認(rèn)為這些代碼比較穩(wěn)定,變量類型不會發(fā)生改變,所以能夠生成高效的本地代碼。但是在實際執(zhí)行過程中,因為JavaScript弱類型語言的特性,變量類型有可能會改變,在這種情況下,V8會將該編譯器做的錯誤優(yōu)化回滾到之前的一般情況,這個過程稱為優(yōu)化回滾。

V8并不只是第一次執(zhí)行一個JavaScript函數(shù)時才編譯它;同一個JavaScript函數(shù)可以被這些JIT編譯器多次編譯。

基本流程是:

    [JavaScript函數(shù)] ->
        第一次被調(diào)用 -> Full Code -> [初級編譯后的代碼]
         足夠熱之后 -> Crankshaft(Optimizing Compiler) -> [優(yōu)化編譯后的代碼]
如果優(yōu)化的代碼需要去優(yōu)化(優(yōu)化回滾) -> deoptimize -> 回到[初級編譯后的代碼]
    ... 周而復(fù)始 ...

示例如下:

var counter = 0;
function test(x,y){
    counter ++;
    if(counter < 10000000){
        // do something
        return 123;
    }
    var unknown = new Date();
    console.log(unknown);
}

函數(shù)test被調(diào)用多次后,V8引擎可能會觸發(fā)Crankshaft編譯器來生成優(yōu)化的代碼,優(yōu)化的代碼認(rèn)為示例代碼的類型等信息都已經(jīng)被獲知,但事實上還未真正執(zhí)行到new Date()這個地方,并未獲取unknown這個變量的類型,V8只得將該部分的代碼進行回滾。優(yōu)化回滾是一個很費時的操作,所以在寫代碼的過程中,盡量不要觸發(fā)這個過程。

二. 隱類型和內(nèi)嵌緩存

我們都知道JavaScript屬于動態(tài)類型語言,只有在運行時才能確定變量的類型,在運行時計算和決定類型,會帶來嚴(yán)重的性能損失,這也就導(dǎo)致了JavaScript語言的運行效率比C++或Java都要低很多。

主要體現(xiàn)在以下幾個部分:

編譯確定位置:
C++在編譯階段對象的屬性和偏移信息都計算完成;而這些信息JavaScript只有在執(zhí)行階段才可以確定

偏移信息共享:
C++屬于靜態(tài)類型語言,不能在執(zhí)行時動態(tài)改變類型,這些對象都是共享偏移信息的。訪問對象時就按編譯時的偏移量即可;JavaScript每個對象都是自描述,屬性和位置偏移信息都包含在自身的結(jié)構(gòu)中。

一個簡單的C++函數(shù):

 class Class1 {
     int x;
     int y;
 }
 int add(Class1 a, Class1 b){
     return a.x*a.y + b.x*b.y;
 }

示例代碼中的類型和對象的結(jié)構(gòu)表示,如下圖:

圖片來源《WebKit技術(shù)內(nèi)幕》

一個簡單的JavaScript函數(shù):

function add(a,b){
    return a.x*a.y + b.x*b.y; // 這里對象a和b的類型未知
}
var a = {x:3.3,y:5.5};
var b = {x:4.4,y:6.6};

示例代碼中對象a和b的結(jié)構(gòu)表示,如下圖:

圖片來源《WebKit技術(shù)內(nèi)幕》

偏移信息查找:
C++中查找偏移地址很簡單,都是在編譯代碼時,對使用到某類型的成員變量直接設(shè)置偏移量。而對于JavaScript,使用到一個對象則需要通過屬性名匹配才能查找到對應(yīng)的值

因為對象屬性的訪問非常普遍而且次數(shù)非常頻繁,像C++這種通過偏移量來訪問值使用少數(shù)兩個匯編指定就能完成,但是Javascript這種通過屬性名來匹配對于性能造成的影響可能會多很多倍,因為屬性名匹配需要特別長的時間,而且額外浪費很多內(nèi)存空間。

有方法解決這一問題么?答案是肯定的。下面我們就來看一下V8引擎是如何解決這一問題的。雖然JavaScript語言沒有類型的定義,但是V8使用類和偏移位置思想,將本來需要通過字符串匹配來查找屬性值的算法改進為使用類似C++編譯器的偏移位置的機制來實現(xiàn)。這就是隱藏類(Hidden Class)

JavaScript對象的實現(xiàn)在V8中包含3個成員,第一個是隱藏類的指針,這是V8為JavaScript對象創(chuàng)建的隱藏類。第二個指向這個對象包含的屬性值。第三個指向這個對象包含的元素。


圖片來源《WebKit技術(shù)內(nèi)幕》

隱藏類將對象劃分成不同的組,對于相同的組,也就是該組內(nèi)的對象擁有相同的屬性名和屬性值的情況,將這些屬性名和對應(yīng)的偏移位置保存在一個隱藏類中,組內(nèi)的所有對象共享該信息。同時,也可以識別屬性不同的對象。

V8引擎的發(fā)展歷史

2008年9月,V8的第一個版本隨著Chrome的第一版發(fā)布。

2010年12月,官方公布V8的名為Crankshaft的優(yōu)化編譯器,與原來的Full Compiler一起工作,聲稱較2008年版本提高50%性能。

2015年7月7日,官方公布又一個新的中為TurBoFan的優(yōu)化編譯器,主要提供ES6的新語法,以及提高性能。并表明該編譯器最終目標(biāo)是全部替代Crankshaft編譯器。

2015年7月17日,官方公布集成了TurboFan的V8版本(v4.5)

2015年8月28日,V8發(fā)布v4.6版本

2016年3月15日,V8發(fā)布v5.0版本

2016年7月18日,V8發(fā)布v5.3版本,新增名為Ignition的解析器(Interpreter),跟原有的優(yōu)化編譯器(Crankshaft and TurboFan)進行串聯(lián)工作,提供了更加優(yōu)化的內(nèi)存使用方案,主要針對于低內(nèi)存的Android設(shè)備,并稱在未來會普及到全平臺。

2016年9月9日,V8發(fā)布v5.4版本

2016年10月24日,V8發(fā)布v5.5版本,在5.5版本中開始支持ES7異步函數(shù),這使得編寫使用和創(chuàng)建Promise的代碼變得更加容易。

2016年12月2日,V8發(fā)布v5.6版本,從5.6版本開始,V8可以優(yōu)化整個JavaScript語言。而且,許多語言功能都是通過V8中的新優(yōu)化管道發(fā)送的。該管道使用V8的Ignition解釋器作為基準(zhǔn),并使用V8更強大的TurboFan優(yōu)化編譯器優(yōu)化經(jīng)常執(zhí)行的方法。新的流水線激活了新的語言功能(例如ES2015和ES2016規(guī)范中的許多新功能)或Crankshaft(V8的“經(jīng)典”優(yōu)化編譯器)無法優(yōu)化某種方法(例如try-catch,with)的情況。

2017年2月6日,V8發(fā)布v5.7版本

2017年3月20日,V8發(fā)布v5.8版本

2017年4月27日,V8發(fā)布v5.9版本,V8 5.9將成為默認(rèn)啟用Ignition + Turbofan的第一個版本。一般來說,這種交換機應(yīng)該可以降低內(nèi)存消耗,并且可以更快地啟動Web應(yīng)用程序。

2017年6月9日,V8發(fā)布v6.0版本,V8 6.0引入了對SharedArrayBuffer的支持,SharedArrayBuffer是一種在JavaScript工作人員之間共享內(nèi)存并在工作人員之間同步控制流的低級機制。 SharedArrayBuffers為JavaScript提供了對共享內(nèi)存,原子和futex的訪問。 SharedArrayBuffers還解鎖了通過asm.js或WebAssembly將線程化應(yīng)用程序移植到Web的功能。

2017年8月3日,V8發(fā)布v6.1版本

2017年9月11日,V8發(fā)布v6.2版本

2017年10月25日,V8發(fā)布v6.3版本,改進了速度和內(nèi)存消耗,詳細(xì)

2017年12月19日,V8發(fā)布v6.4版本,提升了速度和優(yōu)化內(nèi)存消耗,詳細(xì)

2018年2月1日,V8發(fā)布v6.5版本,編譯速度顯著提升,詳細(xì)

2018年3月27日,V8發(fā)布v6.6版本,異步性能大幅提升,詳細(xì)

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/94202.html

相關(guān)文章

  • JavaScript工作原理(二):V8引擎和5招高效代碼

    摘要:引擎可以用標(biāo)準(zhǔn)解釋器或即時編譯器來實現(xiàn),即時編譯器以某種形式將代碼編譯為字節(jié)碼。這里的主要區(qū)別在于不生成字節(jié)碼或任何中間代碼。請注意,不使用中間字節(jié)碼表示法,不需要解釋器。這允許在正常執(zhí)行期間非常短的暫停。 本系列的第一篇文章重點介紹了引擎,運行時和調(diào)用棧的概述。第二篇文章將深入V8的JavaScript引擎的內(nèi)部。我們還會提供一些關(guān)于如何編寫更好的JavaScript代碼的技巧。 概...

    leone 評論0 收藏0
  • JavaScript是如何工作的:深入V8引擎&編寫優(yōu)化代碼的5個技巧

    摘要:第二篇文章將深入谷歌的引擎的內(nèi)部。引擎可以實現(xiàn)為標(biāo)準(zhǔn)解釋器,或者以某種形式將編譯為字節(jié)碼的即時編譯器。這個引擎是在谷歌中使用的,但是,與其他引擎不同的是也用于流行的。一種更復(fù)雜的優(yōu)化編譯器,生成高度優(yōu)化的代碼。不是唯一能夠做到的引擎。 本系列的 第一篇文章 主要介紹引擎、運行時和調(diào)用堆棧。第二篇文章將深入谷歌 V8 的JavaScript引擎的內(nèi)部。 想閱讀更多優(yōu)質(zhì)文章請猛戳GitHu...

    Turbo 評論0 收藏0
  • JavaScript是如何工作的:深入V8引擎&編寫優(yōu)化代碼的5個技巧

    摘要:第二篇文章將深入谷歌的引擎的內(nèi)部。引擎可以實現(xiàn)為標(biāo)準(zhǔn)解釋器,或者以某種形式將編譯為字節(jié)碼的即時編譯器。這個引擎是在谷歌中使用的,但是,與其他引擎不同的是也用于流行的。一種更復(fù)雜的優(yōu)化編譯器,生成高度優(yōu)化的代碼。不是唯一能夠做到的引擎。 本系列的 第一篇文章 主要介紹引擎、運行時和調(diào)用堆棧。第二篇文章將深入谷歌 V8 的JavaScript引擎的內(nèi)部。 想閱讀更多優(yōu)質(zhì)文章請猛戳GitHu...

    DevWiki 評論0 收藏0
  • [譯文] JavaScript工作原理:V8引擎內(nèi)部+5條優(yōu)化代碼的竅門

    摘要:本文將會深入分析的引擎的內(nèi)部實現(xiàn)。該引擎使用在谷歌瀏覽器內(nèi)部。同其他現(xiàn)代引擎如或所做的一樣,通過實現(xiàn)即時編譯器在執(zhí)行時將代碼編譯成機器代碼。這可使正常執(zhí)行期間只發(fā)生相當(dāng)短的暫停。 原文 How JavaScript works: inside the V8 engine + 5 tips on how to write optimized code 幾周前我們開始了一個系列博文旨在深入...

    dreamans 評論0 收藏0
  • JavaScript 工作原理之二-如何在 V8 引擎中書寫最優(yōu)代碼的 5 條小技巧(譯)

    摘要:本章將會深入谷歌引擎的內(nèi)部結(jié)構(gòu)。一個引擎可以用標(biāo)準(zhǔn)解釋程序或者即時編譯器來實現(xiàn),即時編譯器即以某種形式把解釋為字節(jié)碼。引擎的由來引擎是由谷歌開源并以語言編寫。注意到?jīng)]有使用中間字節(jié)碼來表示,這樣就不需要解釋器了。 原文請查閱這里,略有刪減。 本系列持續(xù)更新中,Github 地址請查閱這里。 這是 JavaScript 工作原理的第二章。 本章將會深入谷歌 V8 引擎的內(nèi)部結(jié)構(gòu)。我們也會...

    PingCAP 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<