Javascript Hidden Classes and Inline Caching in V8

Hidden Classes

Javascript,眾所周知是一門動態類型語言,也就是說當一個對象被實例化之后,我們仍然可以隨意的添加或者刪除它的屬性。例如,下面的代碼中,我們實例化了一個car,包含有makemodel兩個屬性,同時,當car被實例化了之后我們仍可以將其他屬性year賦予它。

```javascript
var car = function(make,model) {
    this.make = make;
    this.model = model;
}

var myCar = new car(honda,accord);

myCar.year = 2005;

大多數的JavaScript解釋器通過類字典(dictionary-like,基于hash的)型的對象來存儲對象中的屬性。這樣,相對于非動態類型語言(比如Java),這種結構的數據類型讓我們在獲取對象屬性時會消耗更多的時間。在Java中,所有的對象屬性會在編譯之前就被一個固定的對象層所決定,同時在運行時不可修改。因此,這些屬性的值(或者指向屬性的指針)可以一個接一個的連續得存儲在內存中,每一個屬性都有一個固定的偏移量。偏移量可以簡單的通過屬性的類型決定,顯而易見,由于JavaScript是一門動態類型語言,所以無法在運行時確定偏移量。

在非動態類型語言中,例如Java只需要一條指令就可以確定一個屬性在內存中的位置,然而JavaScript則需要多條指令來從Hash Table中獲得位置。這就導致在JavaScript中屬性查找通常會比其他語言慢很多。

鑒于基于字典的存儲方式非常的低效,V8采用了一個完全不同的方式:Hidden Class。除了JavaScript是在運行時完成一系列操作之外,Hidden Class的工作原理和Java中對待對象的處理方式很類似。在閱讀剩下的文章時,請記住V8會給每一個對象都賦予一個Hidden Class,Hidden Class的終極目的就是優化屬性的查詢時間。現在我們來具體看看。

function Point(x,y) {
    this.x = x;
    this.y = y;
}

var obj = new Point(1,2);

一旦一個新的function被聲明,JavaScript就會緊接著創建一個Hidden Class C0

enter image description here
enter image description here

由于暫時還沒有屬性,所以C0是空的。

當執行到this.x = x時,V8會創建第二個Hidden Class叫做C1C1是基于C0的。C1描述了如何找到屬性x,也就是x在內存中的位置。在這個例子中,簡化為將x存在偏移值為0的位置,這表明當我們在內存中查看Point對象時,第一個偏移所在的位置會保存屬性x。V8同時會用class transitionC0更新,簡單來說就是Hidden Class現在切換為C1了。換句話說,C1就變成了Point對象的Hidden Class。

enter image description here
enter image description here

每當對象有新屬性加入時,舊的Hidden Class就會通過一個過渡路徑(transition path)更新為新的Hidden Class。這種過渡非常重要,因為這保證了用相同方式創建的兩個對象可以共享同一個Hidden Class。如果有兩個對象共享同一個Hidden Class,同時又有一個屬性同時添加給了這兩個對象,則這種過渡操作保證了新的Hidden Class仍然是這兩個對象的Hidden Class。

this.y = y執行時,重復之前的操作。一個新的叫做C2的Hidden Class被創建,一個過渡會添加給C1,同時Hidden Class轉換為C2Point對象的Hidden Class現在就被更新為了C2

enter image description here
enter image description here

注意:Hidden Class的過渡取決于屬性被添加的順序。

function Point(x,y) {
  this.x = x;
   this.y = y;
}

var obj1 = new Point(1,2);
var obj2 = new Point(3,4);

obj1.a = 5;
obj1.b = 10;

obj2.b = 10;
obj2.a = 5;

var obj2 = new Point(3,4);為止,obj1和obj2共享同一個Hidden Class。但是,由于屬性ab在之后被添加的順序不同,導致了Hidden Class過渡時走向和不同的路徑。

enter image description here

通過上述的例子,也許你直觀上會覺得obj1和obj2擁有不同的Hidden Class并沒有什么關系。因為每一個Hidden Class都保存著合適的偏移量,那么不管obj1和obj2有沒有共享同一個Hidden Class,他們獲取屬性的速度應該是一樣的。為了理解為什么這樣的想法是錯的,讓我們來學習一個V8中的優化技術,叫做內聯緩存(inline caching)。

內聯緩存

V8利用了一個在動態類型語言中常用的優化技巧,內聯緩存。簡單來說,內聯緩存依賴于同類型對象的同一方法的重復調用。

那么這是怎么實現的呢?V8維護了一個緩存——最近被調用的函數中,被作為參數傳遞的對象類型,然后利用這些信息并假設這種對象類型在將來仍然會被作為參數傳遞。如果V8能正確的做出這種預測,那么它就能繞過尋找對象屬性的過程,直接從對象的Hidden Class中尋找之前存好的信息。

好的,那么Hidden Class的思想是這么和內斂緩存相結合起來的呢?當一個特定的對象的方法被調用時,V8引擎需要利用對象的Hidden Class來決定用哪個偏移量來尋找屬性。當針對同一個Hidden Class的方法被成功調用兩次,V8就會跳過Hidden Class的屬性尋找,直接將屬性的偏移量綁定到對象的指針上。當該方法再次被調用時,V8引擎假定Hidden Class沒有被修改,我們可以直接用上次在Hidden Class中查找到的屬性偏移量來去內存中尋找具體的值。這大大提高了執行的速度。

這就是為什么屬性的添加順序顯得很重要了。如果屬性的添加順序不同,兩個對象的Hidden Class就不同,也就無法使用內斂緩存優化了。

enter image description here

當然,鑒于JavaScript仍然是門動態類型語言,所以總會有判斷失誤的時候。這時候就需要返回傳統的方法,利用Hidden Class來獲取屬性的偏移量了。

一些優化技巧

  1. 實例化對象時永遠保存屬性的順序相同。
  2. 給對象增加新的屬性時,會導致Hidden Class更新,同時針對舊Hidden Class的優化失效,導致速度變慢。因此,盡量在構造函數中確定好對象的屬性。
  3. 運行同一個方法多次會比運行多個方法一次要快的多(參照內聯緩存)。
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,030評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,310評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,951評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,796評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,566評論 6 407
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,055評論 1 322
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,142評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,303評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,799評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,683評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,899評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,409評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,135評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,520評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,757評論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,528評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,844評論 2 372

推薦閱讀更多精彩內容