Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

【JavaScript】垃圾回收机制 #31

Open
Tracked by #6
swiftwind0405 opened this issue Mar 29, 2020 · 1 comment
Open
Tracked by #6

【JavaScript】垃圾回收机制 #31

swiftwind0405 opened this issue Mar 29, 2020 · 1 comment

Comments

@swiftwind0405
Copy link
Owner

swiftwind0405 commented Mar 29, 2020

作为一种高级语言,JS 负责几个低级别的管理,比如内存管理。对于大多数编程语言来说,垃圾回收是一个常见的过程。通俗地说,垃圾回收就是简单地收集和释放,那些已经分配给对象,但目前又不被程序任一部分使用的内存。在像 C 这样的编程语言中,开发者必须使用 malloc() 和 dealloc() 函数来处理内存分配和回收。
Javascript 具有自动垃圾回收机制,会定期对那些我们不再使用的变量、对象所占用的内存进行释放。

Javascript 的垃圾回收机制

Javascript 会找出不再使用的变量,不再使用意味着这个变量生命周期的结束。Javascript 中存在两种变量——全局变量和局部变量,全部变量的声明周期会一直持续,直到页面卸载。而局部变量声明在函数中,它的声明周期从执行函数开始,直到函数执行结束。在这个过程中,局部变量会在堆或栈上被分配相应的空间以存储它们的值,函数执行结束,这些局部变量也不再被使用,它们所占用的空间也就被释放。

但是有一种情况的局部变量不会随着函数的结束而被回收,那就是局部变量被函数外部的变量所使用,其中一种情况就是闭包,因为在函数执行结束后,函数外部的变量依然指向函数内的局部变量,此时的局部变量依然在被使用,所以也就不能够被回收

可达性

JavaScript 中内存管理的主要概念是可达性。

简单地说,“可达性” 值就是那些以某种方式可访问或可用的值,它们被保证存储在内存中。

1. 有一组基本的固有可达值,由于显而易见的原因无法删除。例如:

  • 本地函数的局部变量和参数

  • 当前嵌套调用链上的其他函数的变量和参数

  • 全局变量

  • 还有一些其他的,内部的

这些值称为根。

2. 如果引用或引用链可以从根访问任何其他值,则认为该值是可访问的。

例如,如果局部变量中有对象,并且该对象具有引用另一个对象的属性,则该对象被视为可达性, 它引用的那些也是可以访问的。

JavaScript 引擎中有一个后台进程称为垃圾回收器,它监视所有对象,并删除那些不可访问的对象。

垃圾回收的算法

引用计数法

引用计数法就是引用对引用的次数进行计数。如果引用了增加就加 1,引用减少就减去 1。当引用等于 0 时将它清除。

引用计数有一个致命的问题就是循环引用,如果两个对象互相引用,尽管不再使用但是会进入一个无限循环,垃圾回收器不会对他进行回收。现在一般不会使用这个方法,但是 ie9 之前仍然还在用。

标记清除算法

标记清除算法是目前使用的较多的方法

基本的垃圾回收算法称为标记-清除,定期执行以下“垃圾回收”步骤:

  • 垃圾回收器获取根并标记(记住)它们。
  • 然后它访问并“标记”所有来自它们的引用。
  • 然后它访问标记的对象并标记它们的引用。所有被访问的对象都被记住,以便以后不再访问同一个对象两次。
  • 以此类推,直到有未访问的引用(可以从根访问)为止。
  • 除标记的对象外,所有对象都被删除。

例如,对象结构如下:

image

我们可以清楚地看到右边有一个“不可到达的块”。现在让我们看看“标记并清除”垃圾回收器如何处理它。

  • 第一步标记根:
    image
  • 然后标记他们的引用:
    image
  • 以及子孙代的引用:
    image
  • 现在进程中不能访问的对象被认为是不可访问的,将被删除:
    image

标记清除算法数据结构

标记清除法利用到了堆、链表结构 标记阶段:从根集合出发,将所有活动对象及其子对象打上标记 清除阶段:遍历堆,将非活动对象(未打上标记)的连接到空闲链表上

内存泄露

本质上讲,内存泄露就是不再被需要的内存,由于某种原因,无法被释放。

常见的内存泄露案例

  1. 全局变量造成内存泄露

    尽量不要使用全局变量。

  2. 未销毁的定时器和回调函数造成内存泄露

    使用玩及时清理定时器和回调函数。

  3. 闭包造成内存泄露
  4. DOM 引用造成内存泄露

    可以使用 WeakMap 或者 WeakSet 存储 DOM节点,DOM 被移除掉 WeakMap 或者 WeakSet 内部的 DOM 引用会被自动回收清除。

尽管垃圾回收是 JavaScript 自动执行的,但在某些情况下,它可能并不完美。在 JavaScript ES6 中,Map 和 Set 与它们的“weaker”兄弟元素一起被引入。“weaker”对应着 WeakMap 和 WeakSet,持有的是每个键对象的“弱引用”。它们允许对未引用的值进行垃圾收集,从而防止内存泄漏。

参考资料

@swiftwind0405 swiftwind0405 changed the title 【】垃圾回收机制 【Day31】垃圾回收机制 Mar 29, 2020
@swiftwind0405
Copy link
Owner Author

  • 什么是强引用,弱引用,循环引用

@swiftwind0405 swiftwind0405 changed the title 【Day31】垃圾回收机制 【JavaScript】垃圾回收机制 Apr 29, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant