[译] 通过垃圾回收机制理解 JavaScript 内存管理

栏目: JavaScript · 发布时间: 6年前

内容简介:照片来自Unsplash 上的Dlanor S内存管理的主要目标是在需要的时候为系统动态地分配内存,然后释放那些不再使用的对象的内存。像 C、C++ 这样的语言有基本的内存分配函数,如JavaScript 引擎的垃圾回收器基本上是寻找内存中被删除的无法访问的对象。这里我想解释两种垃圾回收算法,如下所示:
[译] 通过垃圾回收机制理解 JavaScript 内存管理

照片来自Unsplash 上的Dlanor S

内存管理的主要目标是在需要的时候为系统动态地分配内存,然后释放那些不再使用的对象的内存。像 C、C++ 这样的语言有基本的内存分配函数,如 malloc() ,而一些高级语言计算机体系结构(如 JavaScript)包含垃圾回收器来完成这项工作。它跟踪内存分配并识别这些分配的内存是否不再使用,如果是就自动释放。但是这种算法不能完全决定内存是否仍被需要。因此,对于 程序员 来说,理解并决定一段特定的代码是否需要内存是非常重要的。让我们了解一下 JavaScript 中的垃圾收集是如何工作的:

垃圾回收

JavaScript 引擎的垃圾回收器基本上是寻找内存中被删除的无法访问的对象。这里我想解释两种垃圾回收算法,如下所示:

  • 引用计数垃圾回收
  • 标记清除算法

引用计数垃圾回收

这是一个简单的垃圾回收算法。这个算法寻找那些没有被引用的对象。如果一个对象没有被引用,那么该对象就可以被垃圾回收。

var obj1 = {
    property1: {
         subproperty1: 20
     }
};
复制代码

如上例所示,让我们创建一个对象以理解这个算法。这里 obj1 引用了一个对象,其中的 property1 属性也引用了一个对象。由于 obj1 具有对象的引用,因此这个对象不会被垃圾回收。

var obj2 = obj1;

obj1 = "some random text"
复制代码

现在, obj2 也引用了被 obj1 引用的同一个对象,但后来 obj1 被更新为了 "some random text" ,这导致 obj2 具有对该对象的唯一引用。

var obj_property1 = obj2.property1;
复制代码

现在 obj_property1 指向 obj2.property1 ,它引用了一个对象。因此该对象有两个引用,如下所示:

obj2
obj_property1
obj2 = "some random text"
复制代码

通过更新为 "some random text" 来取消 obj2 对对象的引用。因此,之前的这个对象似乎没有被引用了,所以它可以被垃圾回收。但是,由于 obj_property1 具有 obj2.property1 的引用,因此它不会被垃圾回收。

obj_property1 = null;
复制代码

当我们把 obj_property1 引用删除,现在最初 obj1 指向的对象没有引用了。所以现在它可以被垃圾回收。

这个算法在哪里失败了?

function example() {
     var obj1 = {
         property1 : {
              subproperty1: 20
         }
     };
     var obj2 = obj1.property1;
     obj2.property1 = obj1;
     return 'some random text'
}

example();
复制代码

这里引用计数算法在函数调用之后不会从内存中删除 obj1obj2 ,因为两个对象都是相互引用的。

标记清除算法

这个算法查找从根开始无法访问的对象,这个根是 JavaScript 的全局对象。该算法克服了引用计数算法的局限性。没有引用的对象是不可访问的,但是反过来就不一定了。

var obj1 = {
     property1: 35
}
复制代码
[译] 通过垃圾回收机制理解 JavaScript 内存管理

如上所示,我们可以看到创建的对象 obj1 如何从 ROOT 中访问到的。

obj1 = null
复制代码
[译] 通过垃圾回收机制理解 JavaScript 内存管理

现在,当我们将 obj1 的值设置为 null 时,该对象从根开始无法被访问,因此它可以被垃圾回收。

该算法从根开始,遍历所有其他对象,同时标记它们。它进一步遍历被遍历的对象并标记它们。这个过程将被重复直到所有已被遍历的节点没有任何子节点和可遍历的路径。现在垃圾回收器会忽略所有可访问对象,因为它们在遍历时被标记。因此,所有未标记的对象显然都是从根节点开始无法访问的,这意味着它们可以被垃圾回收,稍后通过删除这些对象释放内存。让我们通过下面的例子来试着理解一下:

[译] 通过垃圾回收机制理解 JavaScript 内存管理

如上所示,这就是对象结构的样子。我们可以注意到无法从根开始访问的对象,但是让我们尝试了解在这种情况下标记清除算法是如何工作的。

[译] 通过垃圾回收机制理解 JavaScript 内存管理

算法从根开始标记遍历到的对象。上面的图片中,我们可以注意到在对象上标记的绿色圆圈。这样它就可以将对象标识为可从根开始可以访问到。

[译] 通过垃圾回收机制理解 JavaScript 内存管理

未被标记的对象是无法从根开始被访问到的。因此它们可以被垃圾回收。


以上所述就是小编给大家介绍的《[译] 通过垃圾回收机制理解 JavaScript 内存管理》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Building Social Web Applications

Building Social Web Applications

Gavin Bell / O'Reilly Media / 2009-10-1 / USD 34.99

Building a social web application that attracts and retains regular visitors, and gets them to interact, isn't easy to do. This book walks you through the tough questions you'll face if you're to crea......一起来看看 《Building Social Web Applications》 这本书的介绍吧!

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具