JavaScript 核心觀念(8)-執行環境與作用域-記憶體存放與釋放

前言

接下來講一下記憶體的回收機制。

Garbage collection

回收機制

Garbage collection 中文名稱又稱為垃圾回收,垃圾回收是一個自動化記憶體管理機制,當某一段程式碼行時,都會暫用一些記憶體,如果沒有 Garbage collection 的機制,那麼記憶體就會很快速的滿出來導致出現所謂的 Lag 等問題,拿生活面的舉例來講,回收機制就像一個契約,當你租一台汽車兩天,那麼你就必須在第二天時歸還汽車(回收),否則汽車車商就沒有汽車可以租給別人。

在早期的程式語言其實並沒有 Garbage collection 的機制,因此在開發系統上對於記憶體的管理就會相對注重,你可以看到以前相當多的技術書本都會提到記憶體管理,因此 Garbage collection 的存在可以大大減少工程師的負擔,相對在撰寫 JavaScript 這也是一個相當重要的觀念。

JavaScript 是如何回收記憶體

前面章節我們了解到每一個函式都有屬於它的記憶體空間

1
2
3
4
5
6
function a() { // a 的記憶體空間

}
function b() { // b 的記憶體空間

}

當我們執行 a()b() 就會佔用一些記憶體空間,當執行完畢後就會像前面的執行堆疊中的函式釋放一樣釋放記憶體

函式釋放

但是這邊有一個重點要注意 Garbage collection 要回收的記憶體的依據是依照「當物件不再被使用或是不再被其他物件參考時」,它才會被視為一個可回收的記憶體。

以下截至 MDN

這個演算法將原本「這個物件再也不會被使用」的廣泛定義縮減到「沒有其他任何物件參考它」。如果一個物件不在被任何物件參考,它將被視為可回收記憶體的垃圾。

驗證範例

課程中也有提供一個相當不錯的驗證範例。

1
2
3
4
5
6
7
8
9
function randomString(length) {
var result = '';
var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
var charactersLength = characters.length;
for (var i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
}
return result;
}

上面程式碼簡單來講就是會隨機生成很長很長很長的字串來佔用記憶體,接下來下面這一段程式碼將會持續佔用記憶體空間

1
2
3
4
5
6
7
8
var demoData = [];
function getData() {
for (let i = 0; i < 1000; i++) {
demoData.push(randomString(5000));
}
}
getData();
console.log(demoData);

上面這一段程式碼簡單來講會在全域變數 demoData 塞入字串而暫用記憶體空間,在這邊可以將這兩段程式碼丟進 Chrome 後使用 Memory 紀錄記憶體,看記憶體的變化狀況

記憶體佔用狀況

上述圖片我們可以看到目前記憶體被佔用 9.3 MB,接下來重新整理一下換成以下程式碼

1
2
3
4
5
6
7
8
function getData() {
var demoData = [];
for (var i = 0; i < 1000; i++) {
demoData.push(randomString(5000))
}
console.log(demoData);
}
getData()

在這邊這一段程式碼 demoData 是建立於 getData 中,因此當程式碼執行完畢時,他會釋放掉記憶體也就是 Garbage collection,但是你會發現記憶體還是佔用 9.3 MB

記憶體佔用狀況

這時候你可能會想說「變數不是建立在 getData 嗎?那麼應該會被釋放記憶體呀?」,沒有錯,但記憶體會這樣佔用的原因主要是 console 也會暫用記憶體空間,因此你只需要將 console 清空(不是 Reset) 就會發現記憶體變成 4.3 MB

Console 佔用

參考文獻