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

2019-01-2510:27:10WEB前端开发Comments1,888 views字数 1862阅读模式

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

垃圾回收

JavaScript 引擎的垃圾回收器基本上是寻找内存中被删除的无法访问的对象。这里我想解释两种垃圾回收算法,如下所示:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/9377.html

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

引用计数垃圾回收

这是一个简单的垃圾回收算法。这个算法寻找那些没有被引用的对象。如果一个对象没有被引用,那么该对象就可以被垃圾回收。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/9377.html

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

如上例所示,让我们创建一个对象以理解这个算法。这里 obj1 引用了一个对象,其中的 property1 属性也引用了一个对象。由于 obj1 具有对象的引用,因此这个对象不会被垃圾回收。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/9377.html

var obj2 = obj1;

obj1 = "some random text"
复制代码

现在,obj2 也引用了被 obj1 引用的同一个对象,但后来 obj1 被更新为了 "some random text",这导致 obj2 具有对该对象的唯一引用。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/9377.html

var obj_property1 = obj2.property1;
复制代码

现在 obj_property1 指向 obj2.property1,它引用了一个对象。因此该对象有两个引用,如下所示:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/9377.html

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

通过更新为 "some random text" 来取消 obj2 对对象的引用。因此,之前的这个对象似乎没有被引用了,所以它可以被垃圾回收。但是,由于 obj_property1 具有 obj2.property1 的引用,因此它不会被垃圾回收。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/9377.html

obj_property1 = null;
复制代码

当我们把 obj_property1 引用删除,现在最初 obj1 指向的对象没有引用了。所以现在它可以被垃圾回收。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/9377.html

这个算法在哪里失败了?

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

example();
复制代码

这里引用计数算法在函数调用之后不会从内存中删除 obj1obj2 ,因为两个对象都是相互引用的。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/9377.html


标记清除算法

这个算法查找从根开始无法访问的对象,这个根是 JavaScript 的全局对象。该算法克服了引用计数算法的局限性。没有引用的对象是不可访问的,但是反过来就不一定了。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/9377.html

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

如上所示,我们可以看到创建的对象 obj1 如何从 ROOT 中访问到的。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/9377.html

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

现在,当我们将 obj1 的值设置为 null 时,该对象从根开始无法被访问,因此它可以被垃圾回收。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/9377.html

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

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

如上所示,这就是对象结构的样子。我们可以注意到无法从根开始访问的对象,但是让我们尝试了解在这种情况下标记清除算法是如何工作的。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/9377.html

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

算法从根开始标记遍历到的对象。上面的图片中,我们可以注意到在对象上标记的绿色圆圈。这样它就可以将对象标识为可从根开始可以访问到。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/9377.html

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

未被标记的对象是无法从根开始被访问到的。因此它们可以被垃圾回收。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/9377.html

局限性

对象必须显式地设置为不可访问。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/9377.html

自 2012 年以来,JavaScript 引擎已经使用此算法来代替引用计数垃圾回收。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/9377.html

谢谢阅读。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/9377.html

作者:wuzhengyan2015
链接:https://juejin.im/post/5c4409fbf265da616f703d5a
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/9377.html

文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/9377.html
  • 本站内容整理自互联网,仅提供信息存储空间服务,以方便学习之用。如对文章、图片、字体等版权有疑问,请在下方留言,管理员看到后,将第一时间进行处理。
  • 转载请务必保留本文链接:https://www.cainiaoxueyuan.com/gcs/9377.html

Comment

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定