V8 中的垃圾收集(GC),圖文指南

justjavac發表於2017-09-12

原文標題:Garbage collection in V8, an illustrated guide
原文連結:https://medium.com/@_lrlna/ga...
譯者:@justjavac

本指南與我迄今為止所寫的其他指南都不同,我在裡面新增了一些草圖。我用草圖描繪了垃圾收集(GC)的整個概念以及它是如何在 javascript 中被處理的,更確切地說是在執行 javascript 的引擎中。順便提一下,這個指南是面向初學者的,不包括 V8 記憶體管理的各個方面以及 V8 的內部原理。我新增了一些資源,可以幫助你更深入地瞭解。本指南重點介紹✨javascript✨,對於某些語言而言,垃圾收集是完全不一樣的,比如 C 語言.

好的,我們開始吧。

什麼是v8?

V8,是一個 JavaScript 的執行時引擎,不要與你最喜愛的番茄汁?混淆了,它負責編譯並執行你精美的javascript。V8 帶有分代垃圾收集器,我將在後文解釋。它與 Chrome 一起,而 SpiderMonkey 是 Mozilla 的引擎 Chakra 是微軟的。基本上當執行 javascript 時,您需要一個引擎來處理它,而且 V8 是您的選擇之一,無論是在瀏覽器還是在 node.js 環境中。(P.S. V8 是✨ 開源的 ✨。)

什麼是垃圾收集?

垃圾收集的重點是透過使用特定的程式來管理記憶體的使用。諸如 C 之類的語言通常可以直接操作程式中的記憶體,並在程式的上下文中分配和釋放物件。另一方面,ECMAScript 缺少訪問記憶體管理的特定介面(是的,這意味著沒有API)。這基本上意味著程式中的所有記憶體管理許可權都被轉移到了 V8。

由於我們無法訪問無限量的記憶體,因此垃圾收集器的工作是透過記憶體中分配的物件來確定它們是否死亡或是活動。那些活著的物件會留在記憶體中,那些死亡的物件被刪除,記憶體被分配回堆。

什麼是堆?堆是非結構化區域,堆中的物件佔用分配的記憶體。這種分配是動態的,因為物件的大小/壽命/數量是未知的,所以需要在執行時分配和釋放。

如果我們看一下併發模型,堆直接與呼叫棧一起工作,因為堆疊中的物件需要進行記憶體分配。它看起來像這樣:

Dead or alive?

如何檢查物件的生死,是透過客戶機或者程式程式碼是否可以到達此物件。您可以想到的最容易達到的物件可能是根範圍中定義的物件。

一些 C++ 繫結(或客戶端上的 Web API)也是根的一部分,因此您可以透過例如 setInterval 直接訪問。

可達性(Reachability)還可以這麼理解:另一個物件或根是否可以獲得它,如果可以的話,該物件所需的記憶體被保留。

那麼我們怎麼可以做到垃圾收集呢?(告訴我!告訴我!)

建立新物件或新的“指標”時,V8 會在堆中分配記憶體。(javascript 沒有真正的指標,所以'指標'在技術上只是複製對原始物件的引用)。堆中的不同型別的物件會佔用不同的空間,它將被組織成如下:

為了垃圾回收的目的,V8 將堆分為兩部分:新生區和老生區。當您執行需要 V8 分配記憶體的操作時,V8 將在新生區中分配空間。當你繼續新增到堆,你最終會耗盡記憶體,所以 V8 將不得不執行一個 GC 來清理。新建立的物件被分配得很快,並且當物件死亡時被清理(更短和更快的收集)。一旦物件“生存”了一些(確切的說是2個週期)回收掃描週期時,它們被提升到老生區,在一個單獨的迴圈中收集垃圾。

較舊的物件是倖存多於一個垃圾收集掃描的物件,這意味著它們仍然被其他物件引用,並且仍然需要佔用該記憶體。他們通常不引用較年輕的物件,只是引用較舊的物件。大週期進行的並不頻繁。一次大週期通常是在移動足夠多的物件至老生區後才會發生。

? sources.js

This guide is crossposted from lrlna’s sketchin guide on github ✨ ?.

相關文章