為V8優(yōu)化JavaScript

V8可以讓JavaScript加速350倍,所以我們有很多優(yōu)化的空間幸逆,在這之前纵隔,我們必須了解V8優(yōu)化JavaScript的原理,然后寫出針對V8的代碼嘹承。

下面會使用"Be prepared"這個詞語窗价,單詞的意思是:

  • 理解V8優(yōu)化原理
  • 寫出深思熟慮的JavaScript代碼
  • 使用工具測試性能,幫助改進(jìn)

隱藏類

變量類型對生成高速優(yōu)化的代碼非常有幫助叹卷,但是JavaScript確實若類型的撼港。如何才能讓JavaScript跑的像C++一樣快呢?答案就hidden classes

Hidden Classes讓JavaScript更快

  • V8在內(nèi)部為創(chuàng)建隱藏類
  • 具有相同隱藏類的對象可以使用相同的優(yōu)化代碼

如果不理解上面的原理骤竹,可以查看V8設(shè)計原理或者ppt

tips:使用構(gòu)造函數(shù)初始化數(shù)據(jù)

function Point(x, y) {
 this.x = x;
 this.y = y;
}
var p1 = new Point(11, 22);
var p2 = new Point(33, 44);
p2.z = 55// warning! p1 and p2 now have// different hidden classes

當(dāng)V8解析p2.z = 55時帝牡,p1,p2使用了不同的隱藏類了,就意味著要創(chuàng)建一個新的隱藏類蒙揣,cache也要重建靶溜,所以盡量不要這樣。如果你沒有用構(gòu)造函數(shù)懒震,請保證對象賦屬性的順序是一樣的罩息。

高效的描述值

Be Prepared - Numbers

我們看到下圖中,V8使用一個標(biāo)簽來表示不同的對象挎狸,很明顯對于數(shù)字扣汪,我們使用能用31位有符號整數(shù)是效率最高的断楷。


Tagged Values

Prefer numeric values that can be represented as 31-bit signed integers

var i = 42; // this is a 31-bit signed integer
var j = 4.2; // this is a double-precision floating point number

Be Prepared - Arrays

V8有兩種處理數(shù)組的方式

  • Fast Elements: 線性存貯锨匆,連續(xù)的buffer,性能好
  • Dictionary Elements: hash table storage otherwise

避免性能陷阱

  • 使用從0開始連續(xù)的key
    下面明顯是字典形式,性能不如Fast Elements模式
var person = [];
person["firstName"] = "John";
person["lastName"] = "Doe";
person["age"] = 46;
var x = person.length;         // person.length will return 0
var y = person[0];             // person[0] will return undefined
  • 不要預(yù)先建立太大的數(shù)組(e.g. > 64K elements)恐锣,JavaScript不需要像C語言指定數(shù)組大小
    這樣會變成稀疏數(shù)組茅主,也會使用字典模式創(chuàng)建


    不同的數(shù)組模式
  • 不要刪除數(shù)據(jù),特別是數(shù)值型的數(shù)組
    這樣會導(dǎo)致兩種模式的切換土榴,都會很費時

  • 不要使用未初始化的數(shù)組诀姚,或者被刪除的元素

a = new Array();
for (var b = 0; b < 10; b++) {
  a[0] |= b;  // Oh no! 這里a[0]是undefined,v8會做轉(zhuǎn)換玷禽,結(jié)果是對的赫段,但是更費時間
}
//vs.
a = new Array();
a[0] = 0;
for (var b = 0; b < 10; b++) {
  a[0] |= b;  // Much better! 2x faster.
}
  • 不要導(dǎo)致數(shù)組boxing and unboxing
    看看下圖,既有double矢赁,又有其他類型糯笙,下面會導(dǎo)致hidden class的兩次轉(zhuǎn)變和三次申請空間。如果不理解可以看視頻撩银。


    Paste_Image.png
var a = [77, 88, 0.5, true]; 這樣讓解析器一次知道所有信息會更好

總結(jié)一下使用數(shù)組需要注意的地方:

  1. 使用[]初始化數(shù)組
  2. 小數(shù)組可以先指定大小 (<64k) 给涕,因為會使用快速模式


    小數(shù)組

    指定大小
  3. 不要在數(shù)字?jǐn)?shù)組里面使用非數(shù)字,數(shù)值型的性能已經(jīng)優(yōu)化過额获,包括double
  4. 如果沒有使用數(shù)組字面量初始化數(shù)組够庙,注意不必要的轉(zhuǎn)換發(fā)生

Be Prepared - Full Compiler

V8有兩個編譯器。你沒聽錯抄邀,是編譯器耘眨,JavaScript是動態(tài)語言,一般的動態(tài)語言都由解析器解析執(zhí)行境肾,但是V8可以直接編譯成可執(zhí)行代碼毅桃。

  • "Full" compiler 為所有JavaScript生成可執(zhí)行代碼
  • Optimizing compiler 為大多數(shù)JavaScript代碼生成更優(yōu)化的代碼

"Full" Compiler立刻運行代碼

  • 生成好的但不是最好的JIT代碼,但是支持所有的JavaScript功能
  • 編譯期間并不假定類型信息准夷,并期待類型在運行時變化
  • 運行的時候獲取類型并使用Inline Caches (or ICs)去加速執(zhí)行
    Paste_Image.png

Full Compiler Example

this.isPrimeDivisible = function(candidate) {
  for (var i = 1; i <= this.prime_count; ++i) {
    if (candidate % this.primes[i] == 0) return true;
  }
  return false;
}

candidate % this.primes[i]會編譯成:

生成的匯編代碼使用了IC

生成的匯編代碼使用了IC

IC的目的是加速處理類型信息钥飞,它為JavaScript操作存貯類型相關(guān)的代碼,當(dāng)代碼運行的時候衫嵌,它驗證所假定的類型信息读宙,然后使用IC去處理。所以楔绞,能處理多種類型的操作性能要查一些结闸。

優(yōu)化tips:

單一的操作比多樣的操作好
Monomorphic use of operations is preferred over polymorphic operations

function add(x, y) {
  return x + y;
}

add(1, 2);      // + in add is monomorphic(所有的操作都是數(shù)值類型的話)
add("a", "b");  // + in add becomes polymorphic

Optimizing compiler

優(yōu)化編譯實際上使用inline技術(shù),還記得在C++中的inline嗎酒朵,是一個意思桦锄。短小的函數(shù),并且經(jīng)常調(diào)用的函數(shù)蔫耽,會被編譯器優(yōu)化成inline结耀。一般單一類型的函數(shù)和構(gòu)造函數(shù)會被inline。

我們看一下代碼(**inline可以避免跳轉(zhuǎn)
**):


inline會避免跳轉(zhuǎn)

深度優(yōu)化后更快了

一些有用的命令

d8 --trace-opt primes.js //log names of optimized functions to stdout
d8 --trace-bailout primes.js //找到被try catch包住不能優(yōu)化的函數(shù)
d8 --trace-deopt primes.js //v8必須取消優(yōu)化的代碼,找到以后可以修改
給chrome加啟動參數(shù)
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" \--js-flags="--trace-opt --trace-deopt --trace-bailout"

prime.js是一個測試獲得質(zhì)數(shù)的函數(shù)图甜,ppt的作者用來測試性能用的碍粥。

function Primes() {
  this.prime_count = 0;
  this.primes = new Array(25000);
  this.getPrimeCount = function() { return this.prime_count; }
  this.getPrime = function(i) { return this.primes[i]; }
  this.addPrime = function(i) {
    this.primes[this.prime_count++] = i;
  }

  this.isPrimeDivisible = function(candidate) {
    for (var i = 1; i <= this.prime_count; ++i) {
      if ((candidate % this.primes[i]) == 0) return true;
    }
    return false;
  }
};

function main() {
  p = new Primes();
  var c = 1;
  while (p.getPrimeCount() < 25000) {
    if (!p.isPrimeDivisible(c)) {
      p.addPrime(c);
    }
    c++;
  }
  print(p.getPrime(p.getPrimeCount()-1));
}

main();

你需要編譯v8,獲得d8命令行黑毅,在windows在編譯可以參考這篇文章使用visual studio編譯v8

d8

這些命令跑出來的結(jié)果還看不太懂嚼摩,等以后仔細(xì)研究在來分享
命令結(jié)果案例

本文翻譯自這個ppt,可以觀看youtube演講
這篇文章也很好Performance Tips for JavaScript in V8

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末矿瘦,一起剝皮案震驚了整個濱河市枕面,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌缚去,老刑警劉巖膊畴,帶你破解...
    沈念sama閱讀 218,682評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異病游,居然都是意外死亡唇跨,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評論 3 395
  • 文/潘曉璐 我一進(jìn)店門衬衬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來买猖,“玉大人,你說我怎么就攤上這事滋尉∮窨兀” “怎么了?”我有些...
    開封第一講書人閱讀 165,083評論 0 355
  • 文/不壞的土叔 我叫張陵狮惜,是天一觀的道長高诺。 經(jīng)常有香客問我,道長碾篡,這世上最難降的妖魔是什么虱而? 我笑而不...
    開封第一講書人閱讀 58,763評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮开泽,結(jié)果婚禮上牡拇,老公的妹妹穿的比我還像新娘。我一直安慰自己穆律,他們只是感情好惠呼,可當(dāng)我...
    茶點故事閱讀 67,785評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著峦耘,像睡著了一般剔蹋。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上辅髓,一...
    開封第一講書人閱讀 51,624評論 1 305
  • 那天泣崩,我揣著相機(jī)與錄音少梁,去河邊找鬼。 笑死律想,一個胖子當(dāng)著我的面吹牛猎莲,可吹牛的內(nèi)容都是我干的绍弟。 我是一名探鬼主播技即,決...
    沈念sama閱讀 40,358評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼樟遣!你這毒婦竟也來了而叼?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,261評論 0 276
  • 序言:老撾萬榮一對情侶失蹤豹悬,失蹤者是張志新(化名)和其女友劉穎葵陵,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體瞻佛,經(jīng)...
    沈念sama閱讀 45,722評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡脱篙,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了伤柄。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片绊困。...
    茶點故事閱讀 40,030評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖适刀,靈堂內(nèi)的尸體忽然破棺而出秤朗,到底是詐尸還是另有隱情,我是刑警寧澤笔喉,帶...
    沈念sama閱讀 35,737評論 5 346
  • 正文 年R本政府宣布取视,位于F島的核電站,受9級特大地震影響常挚,放射性物質(zhì)發(fā)生泄漏作谭。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,360評論 3 330
  • 文/蒙蒙 一奄毡、第九天 我趴在偏房一處隱蔽的房頂上張望丢早。 院中可真熱鬧,春花似錦秧倾、人聲如沸怨酝。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽农猬。三九已至,卻和暖如春售淡,著一層夾襖步出監(jiān)牢的瞬間斤葱,已是汗流浹背慷垮。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留揍堕,地道東北人料身。 一個月前我還...
    沈念sama閱讀 48,237評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像衩茸,于是被迫代替她去往敵國和親芹血。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,976評論 2 355

推薦閱讀更多精彩內(nèi)容