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

照片来自 Unsplash 上的 Dlanor Sjavascript

内存管理的主要目标是在须要的时候为系统动态地分配内存,而后释放那些再也不使用的对象的内存。像 C 和 C++ 这样的语言有基本的内存分配函数,如 malloc(),而一些高级语言计算机体系结构(如 JavaScript)包含垃圾回收器来完成这项工做。它跟踪内存分配并识别这些分配的内存是否再也不使用,若是是就自动释放。可是这种算法不能彻底决定内存是否仍被须要。所以,对于程序员来讲,理解并决定一段特定的代码是否须要内存是很是重要的。让咱们了解一下 JavaScript 中的垃圾收集是如何工做的:前端

垃圾回收

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

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

引用计数垃圾回收

这是一个简单的垃圾回收算法。这个算法寻找那些没有被引用的对象。若是一个对象没有被引用,那么该对象就能够被垃圾回收。android

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

如上例所示,让咱们建立一个对象以理解这个算法。这里 obj1 引用了一个对象,其中的 property1 属性也引用了一个对象。因为 obj1 具备对象的引用,所以这个对象不会被垃圾回收。ios

var obj2 = obj1;

obj1 = "some random text"
复制代码

如今,obj2 也引用了被 obj1 引用的同一个对象,但后来 obj1 被更新为了 "some random text",这致使 obj2 具备对该对象的惟一引用。git

var obj_property1 = obj2.property1;
复制代码

如今 obj_property1 指向 obj2.property1,它引用了一个对象。所以该对象有两个引用,以下所示:程序员

  1. 做为 obj2 的属性
  2. 在变量 obj_property1
obj2 = "some random text"
复制代码

经过更新为 "some random text" 来取消 obj2 对对象的引用。所以,以前的这个对象彷佛没有被引用了,因此它能够被垃圾回收。可是,因为 obj_property1 具备 obj2.property1 的引用,所以它不会被垃圾回收。github

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
}
复制代码

如上所示,咱们能够看到建立的对象 obj1 如何从 ROOT 中访问到的。

obj1 = null
复制代码

如今,当咱们将 obj1 的值设置为 null 时,该对象从根开始没法被访问,所以它能够被垃圾回收。

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

如上所示,这就是对象结构的样子。咱们能够注意到没法从根开始访问的对象,可是让咱们尝试了解在这种状况下标记清除算法是如何工做的。

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

未被标记的对象是没法从根开始被访问到的。所以它们能够被垃圾回收。

局限性

对象必须显式地设置为不可访问。

自 2012 年以来,JavaScript 引擎已经使用此算法来代替引用计数垃圾回收。

谢谢阅读。


进一步阅读:

若是发现译文存在错误或其余须要改进的地方,欢迎到 掘金翻译计划 对译文进行修改并 PR,也可得到相应奖励积分。文章开头的 本文永久连接 即为本文在 GitHub 上的 MarkDown 连接。


掘金翻译计划 是一个翻译优质互联网技术文章的社区,文章来源为 掘金 上的英文分享文章。内容覆盖 AndroidiOS前端后端区块链产品设计人工智能等领域,想要查看更多优质译文请持续关注 掘金翻译计划官方微博知乎专栏

相关文章
相关标签/搜索