首頁  >  文章  >  web前端  >  了解JavaScript中的垃圾回收機制

了解JavaScript中的垃圾回收機制

青灯夜游
青灯夜游轉載
2020-11-05 17:53:422042瀏覽

了解JavaScript中的垃圾回收機制

推薦教學:《JavaScript影片教學

#最近看到一些面試的回顧,不少有被面試官問到談談JS 垃圾回收機制,說實話,面試官會問這個問題,說明他最近看到一些關於JS 垃圾回收機制的相關的文章,為了B 格,就會順帶的問問。

最近看到一篇講 JS 垃圾回收的國外文章,覺得講得明白,所以就翻譯過來了,希望對你們有所幫助。

垃圾回收

JavaScript 中的記憶體管理是自動執行的,而且是看不見的。我們創建基本類型、物件、函數……所有這些都需要記憶體。

當不再需要某樣東西時會發生什麼? JavaScript 引擎是如何發現並清理它?

#可達性

JavaScript 中記憶體管理的主要概念是可達性。

簡單地說,「可達性」 值就是那些以某種方式可存取或可用的值,它們被保證儲存在記憶體中。

1. 有一組基本的固有可達值,由於顯而易見的原因無法刪除。例如:

  • 本地函數的局部變數和參數

  • #目前巢狀呼叫鏈上的其他函數的變數和參數

  • 全域變數

  • 還有一些其他的,內部的

##這些值稱為根。

2. 如果引用或引用鏈可以從根存取任何其他值,則認為該值是可存取的。

例如,如果局部變數中有對象,並且該對象具有引用另一個對象的屬性,則該對像被視為可達性, 它引用的那些也是可以訪問的,詳細的例子如下。

JavaScript 引擎中有一個後台程序稱為

垃圾回收器,它監視所有對象,並刪除那些無法存取的對象。

一個簡單的例子

下面是最簡單的例子:

// user 具有对象的引用
let user = {
  name: "John"
};

了解JavaScript中的垃圾回收機制

這裡箭頭表示一個物件參考。全域變數

「user」引用物件 {name:「John」} (為了簡潔起見,我們將其命名為John#)。 John 的 「name」 屬性儲存一個基本類型,因此它被繪製在物件中。

如果 

user 的值被覆寫,則引用遺失:

user = null;

了解JavaScript中的垃圾回收機制

現在 

John 變成不可達的狀態,沒有辦法訪問它,沒有對它的引用。垃圾回收器將丟棄 John 資料並釋放記憶體。

兩個引用

現在讓我們假設我們將引用從

user 複製到admin:

// user具有对象的引用
let user = {
  name: "John"
};
let admin = user;

了解JavaScript中的垃圾回收機制

現在如果我們做同樣的事情:

user = null;

該物件仍然可以透過 

admin 全域變數訪問,所以它在記憶體中。如果我們也覆蓋admin,那麼它可以被釋放。

相互關聯的物件

現在來看一個更複雜的例子, family 物件:

function marry (man, woman) {
  woman.husban = man;
  man.wife = woman;
  return {
    father: man,
    mother: woman
  }
}
let family = marry({
  name: "John"
}, {
  name: "Ann"
})

函數

marry 透過給兩個物件彼此提供引用來「聯姻」它們,並傳回一個包含兩個物件的新物件。

產生的記憶體結構:

了解JavaScript中的垃圾回收機制

到目前為止,所有物件都是可存取的。

現在讓我們刪除兩個引用:

delete family.father;
delete family.mother.husband;

了解JavaScript中的垃圾回收機制

僅僅刪除這兩個引用中的一個是不夠的,因為所有物件仍然是可訪問的。

但如果我們把這兩個都刪除,那麼我們可以看到 

John 不再有傳入的引用:

了解JavaScript中的垃圾回收機制

輸出引用無關緊要。只有傳入的物件才能使物件可訪問,因此,

John 現在是無法存取的,並將從記憶體中刪除所有無法存取的資料。

垃圾回收之後:

了解JavaScript中的垃圾回收機制

無法存取的資料區塊

有可能整個相互連接的物件變得不可存取並從內存中刪除。

來源物件與上面的相同。然後:

family = null;

記憶體中的圖片變成:

了解JavaScript中的垃圾回收機制

這個例子說明了可達性的概念是多麼重要。

很明顯,John和Ann仍然連結在一起,都有傳入的引用。但這還不夠。

“family”物件已經從根上斷開了鏈接,不再有對它的引用,因此下面的整個區塊變得不可到達,並將被刪除。

內部演算法

基本的垃圾回收演算法稱為“標記-清除”,定期執行以下“垃圾回收”步驟:

  • #垃圾回收器取得根並「標記」(記住)它們。

  • 然後它訪問並「標記」所有來自它們的參考。

  • 然後它存取標記的物件並標記它們的參考。所有被訪問的對像都被記住,以便以後不再訪問同一個對象兩次。

  • 以此類推,直到有未存取的參考(可以從根存取)為止。

  • 除標記的物件外,所有物件都被刪除。

例如,物件結構如下:

了解JavaScript中的垃圾回收機制

我們可以清楚地看到右邊有一個「不可到達的區塊」。現在讓我們看看“標記並清除”垃圾回收器如何處理它。

第一步標記根

了解JavaScript中的垃圾回收機制

#然後標記他們的引用

1了解JavaScript中的垃圾回收機制

以及子孫代的引用:

1了解JavaScript中的垃圾回收機制

現在進程中不能存取的物件被認為是不可存取的,將被刪除:

1了解JavaScript中的垃圾回收機制

這就是垃圾收集的工作原理。 JavaScript引擎應用了許多優化,使其運行得更快,並且不影響執行。

一些優化:

  • 分代回收——物件分為兩組:「新物件」和「舊物件」。許多物件出現,完成它們的工作並迅速結 ,它們很快就會被清理乾淨。那些活得足夠久的對象,會變“老”,並且很少接受檢查。

  • 增量回收——如果有很多對象,並且我們試圖一次遍歷並標記整個物件集,那麼可能會花費一些時間,並在執行中會有一定的延遲。因此,引擎試圖將垃圾回收分解為多個部分。然後,各個部分分別執行。這需要額外的標記來追蹤變化,這樣有很多微小的延遲,而不是很大的延遲。

  • 空閒時間收集——垃圾回收器只在 CPU 空閒時運行,以減少對執行的可能影響。

面試怎麼回答

1)問什麼是垃圾

一般來說沒有被引用的物件就是垃圾,就是要被清除, 有個例外如果幾個物件引用形成一個環,互相引用,但根訪問不到它們,這幾個物件也是垃圾,也要被清除。

2)如何檢垃圾

一種演算法是標記 標記-清除 演算法,還想說出不同的演算法可以參考這裡

更深入的講解 V8 之旅: 垃圾回收器

更多程式相關知識,請造訪:程式入門! !

以上是了解JavaScript中的垃圾回收機制的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:segmentfault.com。如有侵權,請聯絡admin@php.cn刪除