本文是V8引擎詳解系列的第六篇,重點內容是關於V8的內存結構,以及一般狀況下內存的使用過程,本文會先從基本概念入手,瞭解V8的堆棧結構,最後描述一個對象建立後在內存中的生命週期(本文不會有太多GC相關內容,關於垃圾回收會在下一篇詳細描述)文末會有已經完成的系列文章的連接,本系列文章還在不斷更新歡迎持續關注。javascript
一般咱們說的計算機由5個部分組成,控制器、運算器、輸出設備、輸出設備、存儲器,而咱們說的內存一般屬於存儲器,而程序運行時CPU須要調用的指令和數據只能經過內存獲取(硬盤只有存儲功能,執行時會將數據緩存到內存中),因此不論是什麼語言的程序,運行時都依賴內存,而內存生命週期基本都是一致的:java
而不少文章講 javascript的內存如何如何,事實上,我認爲這種說法是不許確的,自己javascript只是一種語言,真正進行內存調用分配的是javascript依賴的引擎,本文就來簡單聊一下V8的內存結構。面試
在V8引擎中,能夠先粗獷的分爲兩個部分 棧 和 堆。
那棧指的就是 調用棧,首先棧的特色後進先出(普通意義上棧的特色在這裏不會細說,網上相關文章不少),同時棧空間是連續的,在須要分配空間和銷燬空間操做時,只須要移動下指針,因此很是適合管理函數調用。緩存
而正由於棧空間是連續的,那它的空間就註定是很是有限的,因此不方便存放大的數據,這時咱們就使用了 內存堆 來管理保存一些大數據。bash
這裏要先說一下兩種變量類型:基本類型變量 和 引用變量類型,基礎變量類型包括undefined, null, Number, String, Boolean, Symbol,而引用變量類型包括:Object、Array、Function等等,而實際上在js中Array、Function這些都是基於Objct的,咱們能夠理解引用變量類型指的就是Objct。
(這裏可能有人會說 null不該該是空指針對象類型嗎,typeof null === 'Object'應該算是對象,事實上這裏是一個設計上的歷史遺留問題,而對V8系統來講不管是null和Undefined都只是一個存在與棧裏的固定的值)。ide
由於基礎變量類型的值一般是簡單的數據段,佔用固定大小的空間,因此會存儲在 棧 中,而對象大小不定且一般會佔用較大空間因此會存儲在 堆 中,而在棧空間會保存對象存儲在堆空間的地址。函數
咱們將一段代碼經過一張圖來簡單看一下。post
var a = 123;
var b = 'abc';
var c = {x: 1};
var d = 123;
var f = c;
var g = {x: 1};
複製代碼
基礎類型的值在建立時會開闢一塊內存空間,將內存地址存儲在對應的變量上,若是此時再建立一個基礎類型等同於以前建立過的值,會直接將地址存儲在新建立的變量上,因此就會有 a === d 。學習
那麼若是建立一個對象,就會在堆中開闢一塊空間用來存儲對象,將內存地址存儲在對應的變量上,若是此時建立一個新的變量(f)賦值爲以前所建立的存儲對象地址的變量(c),那麼會將c存儲的堆內存地址賦值給f,就會有 c === f。大數據
若是此時再建立一個新的對象變量g,就會在堆中再開闢一塊空間來建立對象,將地址賦予g,可是即便對象內容同樣,地址不一樣指向的也是兩塊空間,就會有 g !== c。
關於函數調用也很好理解,也是用一段代碼一張圖來表示以下:
function main() {
func1();
}
function func1() {
func2();
func3();
};
function func2() {};
function func3() {};
main();
複製代碼
在函數間的嵌套調用的過程當中外層的函數不會釋放,而棧的空間是有限的也有着嚴格的數量限制,因此在使用遞歸的時候要注意是否會
溢出。
棧的管理一般比較容易一點,經過上下移動指針來管理便可,而堆的管理相對複雜不少,而咱們一般說的垃圾回收等也主要針對堆來講的。
咱們先來看一下內存的結構組成:
(圖片來源: www.imooc.com/article/300…新生代內存區(new space)
新生代內存區會被劃分爲兩個semispace,每一個semispace大小默認爲16MB也就是說新生代內存區一般只有32MB大小(64位),而這兩個semispace分別是from space 和 to space(具體有什麼用下文會說),一般新建立的對象會先放入這兩個semispace中的一個。
老生代內存區(old space)
一般會較爲持久的保存對象,也分爲兩個區域 old pointer space 和 old data space分別用來存放GC後還存活的指針信息和數據信息。
大對象區(large object space)
這裏存放體積超越其餘區大小的對象,主要爲了不大對象的拷貝,使用該空間專門存儲大對象。
單元區、屬性單元區、Map區(Cell space、property cell space、map space)
Map空間存放對象的Map信息也就是隱藏類(Hiden Class)最大限制爲8MB;每一個Map對象固定大小,爲了快速定位,因此將該空間單獨出來。
代碼區 (code Space)
主要存放代碼對象,最大限制爲512MB,也是惟一擁有執行權限的內存
堆內存空間分紅了有不一樣功能做用的空間區域,大對象區,map區,代碼區沒什麼好說的,重點仍是瞭解一下新生代內存區和老生代內存區。
這裏咱們假設建立了一個對象 obj,先說一下新生代內存區的兩個space也就是 from space 和 to space 的做用。
也就是說建立的對象會在to space 和 from space 之間轉移,也就是所謂的 to --> from, from --> to 的角色互換過程。
(本文重點不是垃圾回收,因此不少GC相關的內容不會很詳細)
接下來講一下老生代內存區,如今繼續看上文說的那個對象 obj:
本文主要學習了一些內存的概念以及V8的內存結構,以及各部分的一些做用,事實上不管是面試仍是平常工做中,理解V8的內存機制會對咱們帶來很大幫助,那在下一篇我會重點說一下V8的內存回收機制。若是有什麼錯誤,請在評論中和做者一塊兒討論,若是您以爲本文對您有幫助請幫忙點個贊,感激涕零。
V8引擎詳解(一)——概述
V8引擎詳解(二)——AST
V8引擎詳解(三)——從字節碼看V8的演變
V8引擎詳解(四)——字節碼是如何執行的
V8引擎詳解(五)——內聯緩存
V8引擎詳解(六)——內存結構