渲染就是根據描述或者定義構建一個數據模型,生成圖形的過程。javascript
瀏覽器內核就是將頁面(Html、Css、JavaScript)構建成可視化、可聽化的多媒體結果。html
咱們也能夠將瀏覽器內核稱之爲"渲染引擎",渲染引擎常常作的事情就是將Html、Css、JavaScript文本或者其餘的資源文件轉換成咱們瀏覽器網頁。java
當咱們在執行一段代碼時,真正賦予這段代碼生命的就是JavaScript引擎(JavaScript Engine)。JavaScript引擎是一個專門處理JavaScript腳本的虛擬機,通常會附帶在網頁瀏覽器之中。算法
JavaScript引擎有許多種:chrome
而最爲你們熟知的無疑是V8引擎,他用於Chrome瀏覽器和Node中。 瀏覽器
JavaScript引擎從頭至尾負責整個JavaScript程序的編譯和執行過程。緩存
JavaScript引擎主要組成部分:ide
JavaScript本質上是一種解釋型語言,與編譯型語言不一樣的是它須要一遍執行一邊解析,而編譯型語言在執行時已經完成編譯,可直接執行,有更快的執行速度。函數
V8須要進行垃圾回收,並須要移動這些數據內容,若是直接使用指針的話就會出問題或者須要比較大的開銷。使用句柄就不存在這些問題,只須要修改句柄中的指針便可,使用者使用的仍是句柄,它自己沒有發生變化。工具
管理一系列的小塊內存,這些小內存的生命週期相似,可使用一個Zone對象。 Zone對象先對本身申請一塊內存,而後管理和分配一些小內存。當一塊小內存被分配以後,不能被Zone回收,只能一次性回收Zone分配的全部小內存。例如:抽象語法樹的內存分配和使用,在構建以後,會生成本地代碼,而後其內存被一次性所有收回,效率很是高。
可是有一個嚴重的缺陷,當一個過程須要不少內存,Zone將須要分配大量的內存,卻又不能及時回收,會致使內存不足狀況。
V8使用堆來管理JavaScript使用的數據、以及生成的代碼、哈希表等。爲了更方便地實現垃圾回收,同不少虛擬機同樣,V8將堆分紅三個部分。年輕代、年老代、和大對象。
主要採用Cheney(人名)算法。一種採用複製的方式實現的垃圾回收算法。
一、將新生代堆內存分一爲二,每一部分空間稱爲semispace。其中一個處於使用之中的稱爲from空間,另外一個處於閒置稱爲to空間。
二、當咱們分配對象時,先是在From空間中進行分配。
三、垃圾回收時,檢查from空間內的存活對象,一是否經歷過清除回收,二to空間是否已經使用了25%(保證新分配有足夠的空間)。
四、將這些存活對象複製到to空間中。非存活對象佔用的空間將會被釋放。
五、完成複製後,from空間與to空間角色發生對換。
注:實際使用的堆內存是新生代中的兩個semispace空間大小,和老生代所用內存大小之和。
如何判斷對象是否存活呢?做用域?是一套存儲和查詢變量的規則。這套規則決定了內存裏對象可否訪問。
特色:清除算法是典型的犧牲空間換取時間的算法,沒法大規模地應用到全部回收中,卻很是適合應用在新生代生命週期短的變量。
一、 標記階段遍歷堆中的全部對象,並標記活着的對象
二、 清除階段,只清除沒有被標記的對象。
最大的問題是,在進行一次標記清除以後會出現不連續的狀態。這種內存碎片會對後續的內存分配形成問題。極可能須要分配一個大對象時,全部的碎片空間都沒法完成,就會提早觸發垃圾回收,而此次全量回收是沒必要要的。
在標記清除的基礎上發展而來,在整理的過程當中
一、 將活着的對象往一段移動
二、 移動完成後,直接清理掉邊界外的內存
垃圾回收的過程都須要將應用邏輯暫停下來。爲了下降全量回收帶來的停頓時間,在標記階段,將本來一口氣要完成的動做改成增量標記。垃圾回收與應用邏輯交替執行到標記階段完成。最大停頓時間較少的1/6左右.
後續還引入了延遲清理與增量整理,讓清理和整理動做也變成增量式的。
什麼是上下文(Contexts)?實際是JS應用程序的運行環境,避免應用程序的修改相互影響,例如一個頁面js修改內置對象方法toString,不該該影響到另外頁面。chrome瀏覽器每一個process只有一個V8引擎實例,瀏覽器中的每一個窗口、iframe都對應一個上下文。
利用JS自表達內置對象、方法,如上面代碼實現Math.min方法,從而V8在實現代碼轉譯時只需注重基本操做,以%符號開頭的函數來自V8運行時函數。
V8在創建AST後,對其進行彙編生成動態機器語言,因此AST在code generated後須要回收;針對AST創建過程當中多結點內存申請和一次性回收的特色,V8使用了內存段鏈表管理,並結合scopelock模式,實現少數申請(Segment,8KB~1MB)、屢次分配AST結點、一次回收各個Segment的管理方式,既能避免內存碎片,又能夠避免遍歷AST結點逐個回收內存
對於一段JS代碼,在開始進行詞法分析前,會從編譯緩存區CompilationCache查找該段代碼是否已經被編譯過,若是是,則直接取出編譯過的機器代碼,並返回,這樣下降CPU的使用率,換來內存空間必定的佔用;若是一個頁面中重複加載JS文件,這方法的提速是很明顯的;這種作法應該有平衡對比過。
V8沒有像其它JS Engine使用詞典結構或紅黑樹實現的map來管理屬性,而是在每一個對象附加一個指針,指向hidden class(若是第一次建立該類型對象,則新建hidden class);當對象每添加一個屬性時,將新建一個class(記錄了每一個屬性的位移/位置),而原來的class指向新class,即創建起一個hidden class的轉換鏈表。
函數綁定發生在運行時,因此沒法經過method tables定位函數入口;經過該技術能夠記錄函數入口,避免重複查找。
通常JS engine會在AST生成後,將之編譯爲中間語言(bytecode),在執行時候再解析這些bytecode;Java 也一樣編譯爲這些bytecode,再採用VM(實現跨平臺)做爲解釋器,爲了提升效能,Java採用混雜方式,把無關平臺、經常使用的代碼編譯爲機器代碼。V8則是一次性把AST編譯爲機器語言。從assembler相關文件頭的Copyright能夠看出,這些不一樣平臺(ia32, arm)下的編譯器,原型來自Sun Microsystems。