V8 中的垃圾收集,图文指南

V8 中的垃圾收集,图文指南 原文标题:Garbage collection in V8, an illustrated guide 原文链接:https://medium.com/@_lrlna/ga… 译者:@justjavac 本指南与我迄今为止所写的其他指南都不同,我在里面添加了一些草图。我用草图描绘了垃圾收集(GC)的整个概念以及它是如何在 javascript 中被处理的,更确切地说是在运行 javascrip…

原文标题: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