JavaScript中的垃圾回收(GC)?
JavaScript 的記憶體管理比 C 或 C++ 等低階語言容易得多。與低階語言不同,JavaScript 會自動檢測哪些物件在以後會用到,哪些物件是無用的垃圾,它們佔據記憶體卻沒有理由。在本文中,我們將討論 JavaScript 中的垃圾回收 (GC) 如何工作。我們將詳細討論一些重要的部分:
從根的可達性
互聯物件(不同物件之間的互連)
不可達集合(斷開的連結)
可達性
記憶體管理的第一個概念是可達性。在這種模式下,垃圾收集器嘗試從某個點搜尋可達的值。當某個值或記憶體位置從某個點可達時,它將不會被移除。物件可以直接或間接地從某個位置到達。有一些方法可以確定物件是否可達:
當函式當前正在執行時,其區域性變數和引數可以直接訪問。
如果可以從當前正在執行的函式呼叫其他函式,這些函式也可以訪問。不僅是該函式,鏈中這些函式的引數和區域性變數也將可訪問。
全域性變數始終可訪問
這些直接可訪問的物件稱為根物件。當從根可訪問的其他值也被標記為可訪問時。例如,假設我們有一個物件 ob1 作為我們的全域性物件。由於 ob1 是全域性的,它是根。現在 ob1 中還有一個引用指向 ob2。第二個物件 ob2 並非直接可訪問,但它可以透過根物件 ob1 訪問。因此,它也將被標記為可訪問。當某個物件變得不可訪問時,一個名為垃圾收集器的後臺低優先順序程序將這些不可訪問的物件從記憶體中清除。
示例
使用程式碼和一些圖表顯示了上述思想。
程式碼
let company = { name: "Tutorialspoint" };
該圖描述了一個公司物件指向一個儲存名為“Tutorialspoint”的字串變數的物件。現在這個物件可以透過名為“company”的引用訪問。此時,如果我們將 company 設定為 **null**,則引用將丟失。
程式碼
company = null;
設定 company = null 後,該物件不可訪問。因此,垃圾收集器將在其輪到時移除這部分。
讓我們來看另一個示例,我們在這裡使用兩個引用。讓我們考慮以下程式碼,其中 company 物件由另一個名為 ob 的變數引用。
程式碼
let company = { name: "Tutorialspoint" }; let ob = company;
然後,如果我們設定 company = null,狀態將如下所示:
因此,該物件由另一個名為“ob”的連結引用。換句話說,該物件可以透過“ob”訪問。這就是為什麼垃圾收集器不會將其從記憶體中移除的原因。
互聯物件
Javascript 物件可以與多個物件連結在一起。或者我們可以說它們可以與一些類似的物件互連。在這種情況下,結構變得更加複雜。讓我們來看一個例子來理解互聯物件。
示例
程式碼
function parent(dad, daughter) { dad.daughter = daughter; daughter.dad = dad; return { father: dad, child: daughter } } let parent = parent({ name: "Bob" }, { name: "Alice" });
此示例顯示 parent() 函式建立了兩個物件 father 和 child,名稱分別為“Bob”和“Alice”,這兩個物件透過“dad”和“daughter”關係相互關聯。在下圖中,我們可以直觀地看到這種情況。它表明這兩個物件是互連的。
此時,如果我們刪除一些連線,例如:
程式碼
delete parent_child.father delete parent_child.child.dad
刪除這兩個連結後,father(Bob)沒有傳入連結。垃圾收集器將從記憶體中移除整個 father 物件。此想法在下圖中進行了描述。
不可達島
第三種情況可能是不可達島。考慮上一節(互聯物件)中顯示的相同示例。現在,如果我們刪除父物件的連結,它將分離整個物件,如下面的圖表所示:
父連結已刪除,因此整個物件以及 father 和 child 物件都不可訪問。它們形成了一個不可達島。
程式碼
parent = null;
結論
與任何其他語言一樣,記憶體管理是一項非常重要的任務,最重要的是,清除未使用的記憶體塊對於編寫更好、更高效的程式碼是必要的。JavaScript 自動收集無用記憶體塊的資訊並將其從記憶體中移除。垃圾收集器搜尋從根物件的可達性以確定物件將來是否會被使用。對於互聯物件,它會搜尋物件是否沒有傳入邊,則該物件無法訪問,因此它會將該物件從記憶體中移除。