JavaScript數據類型和內存(內存泄漏、內存垃圾回收)

變量和內存管理

爲了合理的管理內存,操作系統一般會把內存劃分區域來使用,如代碼區、數據區等。被編譯成機器的碼的程序在執行時會被複制到內存的代碼區,程序中的變量和常量會被存放到數據區中。數據區,一般又分成:堆區、棧區、全局區……。各大語言的編譯器的內存模型一般會有一定的差別,不過基本都有堆和棧之分。

對於JavaScript來說,爲了更好的理解,也需要去討論討論堆和棧。

棧區一般由系統自動分配存儲空間,用來存放局部變量、函數形參等一些固定大小的數據,保存在棧區的數據我們一般可以直接操作。因此,JavaScript的基礎數據類型:Number String null undefined Boolean,都是存放在棧區的,是按值訪問的。

在程序執行過程中申請的內存空間屬於堆區,一般存放一些較大且大小不固定的數據,堆區的數據一般不能直接被訪問。堆區空間一般需要程序員手動釋放,若程序員不釋放,程序結束時可能由系統回收 。因此,JavaScript的複雜數據類型(ObjectArrayFunction等)一般放到堆區。由於堆區的數據不能直接訪問,變量的值一般存放的並不是這些數據本身,而是該數據在內存中的地址,因此這些複雜的數據類型,也被成爲引用數據類型。我們訪問一個堆區中的數據步驟一般是這樣的:首先從棧中獲取了該數據的地址引用,然後再從堆內存中取得我們需要的數據。

在這裏插入圖片描述

var a = 20;
var b= 'abc';
var c= true;
var d = {m: 20};

變量的複製

基礎數據類型的變量複製

var a = 20;
// 對於存在棧區的變量,a賦值給b變量,其實是將a變量的值複製一份存到內存中,然後將b變量指向新複製的數據
// 因此a與b其實已經是完全獨立的兩個變量,只是值一樣而已。
var b = a;
console.log(a, b);
b = 30;
console.log(a, b);

在這裏插入圖片描述

複雜數據類型的變量複製

JavaScript是不允許直接訪問堆內存中的數據,所以如果我們要訪問複雜數據類型的時候,採用的是按引用訪問,其實就是在變量對象中存放了一個指向對象的句柄,可以理解爲一個地址,要訪問堆內存中的對象,就要通過這個引用句柄來訪問。

var m = { a: 10, b: 20 };
// 複雜數據類型的賦值,其實是將變量m中存的值(堆中的地址),複製一份出來放到內存中,然後將n指向新複製的值
// 因此,其實m和n最終指向的還是同一個堆中的同一個對象
var n = m;
console.log(m, n);
n.a = 15;
console.log(m, n);

在這裏插入圖片描述

內存泄漏

內存泄露可以定義爲:應用程序或者變量不再需要佔用內存的時候,由於某些原因,該內存並沒有被回收,我們就稱之爲內存泄漏。

內存垃圾回收

垃圾:不再需要的變量或引用即爲垃圾

JavaScript垃圾回收機制常用方法:引用計數標記清除,同時垃圾收集器是週期性運行的。

引用計數

JavaScript中,引用一般是針對複雜數據類型來說的。語言引擎有一張“引用表”,保存了內存裏面所有的資源的引用次數,當引用次數爲0的時候,垃圾回收機制會自動的回收其內存。但是有時候我們會遇到一個值不再需要了,引用數卻不爲0,這種垃圾回收機制是無法釋放這塊內存,這就會導致內存泄漏,比如循環引用的時候。

// 單引用
var a = {name: 'ss'};
// 抹去了a對 {name: 'ss'}的引用
// {name: 'ss'} 的被引用次數就變成0了,所以它就成垃圾了
a = null;

在這裏插入圖片描述

// 循環引用
var a = {name: '666'};
var b = {name: '777'};
a.brother = b;
b.brother = a;
// 即使a和b分別對對象的引用斷掉,其實那兩個對象引用次數依然不爲0
// 但實際上我們已經不需要這兩個對象了
a = null;
b = null;

在這裏插入圖片描述

通過上面的循環引用問題,我們會看到,使用引用計數法進行垃圾回收不是很保險,可能會出現很嚴重的內存泄漏問題。因此,這種垃圾回收機制用的較少,已經很少有瀏覽器使用這種處理方式了。

標記清除

這是JavaScript中最常用的垃圾回收方式。從全局作用域開始,一層一層往下標記,當變量進入執行環境時,就標記這個變量爲“進入環境”。當變量離開環境時,則將其標記爲“離開環境”。所有標記爲“進入環境”的變量不被清除,標記爲“離開環境”的變量會被清除。

使用這種方式,我們可以看到,對於全局變量來說,只要程序還在執行,那麼就不會被刪除,因此我們應該儘量少用全局變量,如果使用完以後,可以手動的將其值改爲null或者使用delete刪除。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章