了解瀏覽器的棧內存 (Stack) & 堆內存 (Heap)

Roy Kwok
5 min readFeb 18, 2019

js 引擎如何在瀏覽器儲存普通類型和對象

JavaScript 的數據類型分為7種:string, number, boolean, null, undefined, symbol, object。

其中 string, number, boolean 合稱為原始類型 (primitive type) 的值;null, undefined 一般則稱為特殊值。至於 object 則稱為合成類型(complex type) 的值,object 是複雜的數據類型,又可分為3個子類型:object, array, function。

這篇文章會針對 object 這個類型,帶出瀏覽器如何處理它。

一般來說,要了解這個過程,你要了解:內存(Ram)與瀏覽器。當你使用瀏覽器時,會佔用了電腦的內存,瀏覽器會將內存再分配給 HTML & CSS 渲染,HTTP 處理,瀏覽器外殼,JS 引擎等等。而 object 的處理就是在 JS 引擎內發生。

棧內存 (Stack) 和堆內存 (Heap)

JS 引擎將得到的內存,並分為代碼區及數據區。而普通類型和對象的區別主要體現在數據區。數據區內則分為棧內存 (Stack) 和堆內存 (Heap)。簡單類型的數據會直接存在 Stack 裡。複雜類型的數據是把 Heap 地址存在 Stack 裡。以下是整個瀏覽器處理數據類型的結構:

以下會通過內存圖概念去解釋數據類型如何存放在 stack 及 heap 之間。

例題一:

var a = 1
var b = a

b = 2
a//等於什麼?

var a = 1,var b = a,內存可以表示為:

當執行b=2直接將2的值放在b的stack中,如:

所以b的改變並沒有影響到a, a=1

例題二:

var a = {name: ‘a’}
var b = a

b = null
a.name//等於什麼?

當執行var a = {name: ‘a’},var b = a時, ab指向相同的ADDR 1(圖2a)。這個時候執行b = null (這是一個普通類型,直接將null的值在stack中給b),導致bheap中的指向消失(圖2b),不會改變heap內存中數據。所以a還是{name: 'a'}

例題三:

var a = {name: ‘a’}
var b = a

b.name = ‘b’
a.name//等於什麼?

當執行var a = {name: ‘a’},var b = a時, ab指向相同的ADDR 1。這個時候執行b.name = 'b' ,更改在heap中地址ADDR 1,所以a.name{name: 'b'}

例題四:

var a = {name: ‘a’}
var b = a

b = {name:’b’}

a.name//等於什麼?

當執行var a = {name: ‘a’},var b = a時, ab指向相同的ADDR 1。這個時候執行b = {name:’b’}(由於這是定義了新的對象),導致bheap中原先指向ADDR 1消失,在heap中新增了ADDR 2,把b指向了ADDR 2,而a沒有變化,所以a.namea

深拷貝和淺拷貝

var a = 1
var b = a
b = 2

上邊的代碼中當對b改變一個完全不受影響,即為深拷貝。對於簡單類型中,賦值就是深拷貝。對於複雜類型(對象),就有深拷貝和淺拷貝一說。因為複雜類型存在引用關係,所以在更改其中一個對象時,兩者的指向還是相同的,即存在一個發生變化,另個也一起變化。

GC垃圾回收機制

如果一個對象沒有被引用就是垃圾,將被回收。

例子:

var fn = function(){};
document.body.onclick=fn
fn = null

//fn = function(){}; 會否被回收?

答案是不會,雖然這個時候執行fn = null (這是一個普通類型,直接將null的值在stack中給向fn),fn被賦值nullfunction(){}的指向消失。但因為document.body.onclick 仍引用function(){},所以沒有被回收。

以上就是有關stack,heap,深拷貝和淺拷貝,GC垃圾回收機制的內容。

--

--

Responses (2)