V8:Chrome的JavaScript引擎,用C++開發,基於ECMA-262第3版標準。作為一個開源項目,任何人都可以參加。項目地址在Google Code:http://code.google.com/p/v8/
Chrome V8設計
自從十九世紀九十年底中,Netscape瀏覽器整合了JavaScript,它使得web開發人員更加容易訪問HTML頁面元素如:表單、frames和圖象。JavaScript迅速流行,用於定製控制項和增加動畫效果。到19世紀九十年代後,出現大量的用於切換圖片以響應使用者產生的滑鼠事件的指令碼。
最近,隨著AJAX的出現,JavaScript已經稱為了實現基於web的應用如:Gmail)的中心技術。JavaScript程式由簡單的幾行成長為幾百k的源碼。然而JavaScript是被設計成實現web應用的非常有效技術。效能已經成為開發基於web的 JavaScript應用的限制因素。
V8是全新的JavaScript引擎,主要設計目標是快速執行大量JavaScript指令碼應用。在幾種benchmark測試中,V8的效能是JScriptIE內的引擎)、SpiderMonkeyFirefox所用)和 JavaScriptCoresafari所用)的許多倍。如果您的web應用受限於JavaScript的執行速度,則使用V8代替您當前的 JavaScript引擎將很可能提高您的應用的效能。效能提升的程度依賴於JavaScript的多少和JavaScript的特點。例如,如果在您的應用中函數傾向於一次一次被執行,則與僅執行一次許多不同函數相比效能將大大地提升。當您閱讀完本文檔時,您將更加清楚效能提升的原因。
V8效能的3個關鍵方面:
◆快速屬性訪問
◆動態產生機器碼
◆高效的記憶體回收
快速屬性訪問
JavaScript是動態程式設計語言:對象的屬性可以增加和刪除。這意味著一個對象的屬性可能改變。大多數JavaScript引擎使用類似字典的資料結構儲存物件的屬性,每個屬性的訪問需要動態尋找定位屬性在記憶體的位置。這種典型的訪問屬性方法比在Java和Smalltalk中訪問執行個體化變數慢得多。在這些語言中,執行個體化變數通過由編譯器決定的根據物件類型定義的對象固定的布局定義的固定的位移來定位。載入或儲存訪問非常簡單,通常僅僅需要一條簡單點的指令。
為了減少訪問JavaScript屬性的時間,V8沒有使用動態尋找訪問屬性,取而代之的是V8動態建立後台隱藏的類。這個想法不是最新才有的-是基於原型的程式設計語言自身的特性相似地用於映射某些東西)見An Efficient Implementation of Self, a Dynamiclly-Typed Object-Oriented Language Based on Prototypes)。在V8中,當一個新的屬性增加時,對象改變它的隱藏類。
為了更加清除說明這一個點,想象如下一個的簡單的JavaScript函數:
function Point(x, y) { this.x = x; this.y = y; }
當new Point(x, y)被執行時一個新的Point對象被建立。當V8首次建立時,V8建立一個初始的隱藏類Point,例子中稱為C0。如果對象初始時沒有任何屬性則定義空的初始類。此處Point對象的隱藏的類是C0。
執行在Point裡第一個語句(this.x = x;)則在Point對象中建立一個新的屬性x, 這種情況下V8:
執行Point的第二個語句(this.y = y; ),則在Point對象中建立一個新的屬性y,這種情況下V8:
無論何時增加屬性,以上似乎通過建立一個隱藏類不是很高效。然而由於類的過渡,隱藏類可以重用,實際的效率較高。第二次建立一個新的Point時是不需要建立新的隱藏類,相反新的Point對象共用了第一個Point對象的類型。例如,如果建立另外一個Point對象:
儘管JavaScript比通常的物件導向的語言更加動態,使用上面方法通常的JavaScript程式的運行時行為將導致高度的結構貢獻。這裡列舉使用隱藏類的兩個優點:屬性訪問不需要字典尋找,同時使得V8能使用物件導向的最佳化,內聯緩衝。更多的內聯緩衝見Efficent Implementation of the Smalltalk-80 System。
動態產生機器指令
首次執行時,V8直接將JavaScript源碼編譯成機器碼。不存在中間過程的位元組碼,沒有解譯器。訪問屬性通過處理內聯的緩衝代碼,這些代碼可以像V8執行時一樣轉為的其他機器指令。
在首次訪問一個給定對象的屬性時,V8產生了對象當前的隱藏類。V8使用隱藏類內部產生內聯緩衝資訊並通過預測這個類是否將用於在同一節代碼的所有將來的對象來最佳化屬性的訪問。如果V8成功預測則屬性的值將用一個簡單的操作讀取或者寫入。如果預測不正確,則V8將刪除被最佳化的代碼。
例如,JavaScript代碼訪問Point對象的屬性x:
point.x
在V8中,訪問x的機器碼是:
# ebx = the point objectcmp [ebx,<hidden class offset>],<cached hidden class>jne <inline cache miss>mov eax,[ebx, <cached x offset>]
如果對象的隱藏類不匹配緩衝的隱藏類,則執行跳轉到V8運行時系統處理內嵌緩衝缺失同時產生內嵌緩衝代碼,通常遇到的情況是匹配,則簡單地返回屬性x的值。
當有許多個物件具有相同的隱藏類時,則就像大多數靜態語言一樣這些對象都受益。使用隱藏類訪問屬性和內嵌緩衝與機器碼產生最佳化組合在一起,對於相同類型的對象以相似的方式頻繁建立和訪問,這將大大地提高執行大多數JavaScript代碼的速度。
高效的記憶體回收
V8回收那些在過程中不再需要的對象的記憶體,這一個過程稱為記憶體回收。為了確保快速的對象分配,記憶體回收時間足夠短暫,沒有記憶體片段,V8使用了stop-the-world,分代,精確記憶體回收行程。這意味著V8:
在V8中,對象的堆分成兩段:剛建立對象的新空間和在記憶體回收時仍在使用的老對象。如果一個對像被記憶體回收行程回收,V8更新所有指向這個對象的指標。