JavaScript之記憶體空間

王振宇發表於2019-03-22

 開發中,宣告變數是每個前端都經常做的一件事,那麼你宣告的變數都是怎麼存放的呢?

開發中的變數按資料型別分為

基本資料型別(Undefined、Null、Number、String、Boolean和Symbol)

引用資料型別(Object)

瀏覽器記憶體空間中有棧和堆,其中

存放基本資料型別以及引用資料型別的記憶體地址

存放引用資料型別

下面我們用圖更加形象的解釋一下棧和堆:

JavaScript之記憶體空間

可以看到,當查詢引用資料型別的時候,先在棧中找到它的記憶體地址,然後通過記憶體地址找到堆中的Object(可能這就是叫做引用資料型別的原因吧)

計算機對棧的讀取要比堆快,而且棧中每個變數佔有固定大小的空間,而Object的大小是變化的(可以對其進行增刪改查操作),所以Object放在堆中,但是棧中存放有它對應的記憶體地址,通過這種方式實現引入資料型別的讀取和操作。

可能程式碼+圖會更加好理解:

let a = 1,b = 'str',c = {name:'c'},d = false;複製程式碼

JavaScript之記憶體空間

接下來我們看幾個例子:

let a = 1;
let b = a;
a = 2;
a // 2
b // 1複製程式碼

let a = 1,在記憶體中開闢a的記憶體1

let b=a,在記憶體中開闢b的記憶體1

a = 2,將a記憶體中的值修改為2

let obj1 = {name:'obj1'};
let obj2 = obj1;
obj1.name = 'obj2';
obj1 // {name:'obj2'}
obj2 // {name:'obj2'}複製程式碼

let obj1 = {name:'obj1'},在堆中儲存物件 {name:'obj1'},並將變數obj1指向該物件的記憶體地址

let obj2 = obj1,在棧中建立obj2的空間,並將其指向{name:'obj1'}的記憶體地址

obj1.name = 'obj2',通過obj1對{name:'obj1'}的引用,修改其name為obj2,所以該物件變為{name:'obj2'}

總結:(源自高程3)

如果從一個變數向另一個變數複製基本型別的值,會在變數物件上建立一個新值,然後把該值複製 到為新變數分配的位置
當從一個變數向另一個變數複製引用型別的值時,同樣也會將儲存在變數物件中的值複製一份放到 為新變數分配的空間中。不同的是,這個值的副本實際上是一個指標,而這個指標指向儲存在堆中的一 個物件。複製操作結束後,兩個變數實際上將引用同一個物件。因此,改變其中一個變數,就會影響另 一個變數

既然說到記憶體,我們就再談一下瀏覽器記憶體空間的管理,如上所述

當宣告一個變數的時候,如果為基本資料型別,瀏覽器會為其在棧中分配記憶體空間,如果為引用資料型別,瀏覽器會為該變數在棧中分配記憶體空間,同時將其宣告的Object存放在堆中,並將該變數指向Object的記憶體地址

接下來是該變數的使用過程(讀,寫)

如果該變數不再被使用,則將其釋放,瀏覽器的垃圾回

而JavaScript 中最常用的垃圾收集方式是標記清除

當變數進入環境的時候(如:變數被宣告),將其標記為‘進入環境’,而當該變數不再需要的時候,則將其標記為‘離開環境’。每隔一段時間,瀏覽器的垃圾收集器就會執行一次,將標記為‘離開環境’的變數回收,並釋放其記憶體。

注:以上為了方便理解對垃圾回收機制做了簡化,有興趣的朋友可以自行查閱高程 4.3

如果有錯誤或者不嚴謹的地方,請給予指正,十分感謝!


相關文章