前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JavaScript垃圾收集

JavaScript垃圾收集

作者头像
流眸
发布2021-04-08 13:18:58
5060
发布2021-04-08 13:18:58
举报

前言

在很多语言中,开发人员的一项基本任务就是手动跟踪内存的使用情况,这是造成许多问题的根源。而 JavaScript具有垃圾收集机制,执行环境会负责管理代码执行过程中使用的内存。因此在编写 JavaScript 程序时,开发人员不用在关心内存使用问题。

“原理:找出那些不再继续使用的变量,释放其所占用的内存。垃圾收集器会按固定的时间间隔,周期性的执行这一操作。

两种策略

1. 标记清除

JavaScript中最常用的垃圾收集方式是标记清除,当变量进入环境时,将此变量做标记为进入环境。逻辑上讲,永远不能释放进入环境的变量所占用的内存,因为只要执行流进入相应的环境,就可能会用到它们。而在变量离开环境时,在此标记其为离开环境

工作流程

  1. 垃圾收集器在运行的时候,会给存储在内存中的所有变量加上标记
  2. 然后,它会去掉环境中的变量以及被环境中的变量引用的变量的标记
  3. 在此之后再被加上标记的变量被看作准备删除的变量,原因是环境中的变量已经无法再访问到这些变量
  4. 最后,垃圾收集器完成内存清除工作,销毁那些带标记的值并回收它们所占用的内存空间

2. 引用计数

另一种不常用的垃圾收集策略是引用计数

“引用计数的含义是跟踪记录每个值被引用的次数。

工作流程

  1. 当声明了一个变量并将一个引用类型赋值给该变量,则这个值的引用次数就是1
  2. 如果这个值又被赋值给另一个变量,则该值的引用次数加1
  3. 相反,如果包含对这个值引用的变量又取得了另外一个值,则这个值的引用减1
  4. 当这个值的引用次数变成0时,则说明没有办法再访问到这个值了,因而可以将其所占用的空间给收回来
  5. 这样,等垃圾收集器下次运行时,便会释放那些引用次数为0的值所占用的内存空间

存在问题

在这样的策略下,出现了比较严重的问题:循环引用

“循环引用指的是对象A中包含了一个指向对象B的指针,而对象B中也含有一个指向对象A的指针。

例:

function problem() {
    var objA = new Object();
    var objB = new Object();
    
    objA.someOtherObject = objB;
    objB.anotherObject = objA;
}

在此例子中,objA 和 objB 都通过各自的属性相互引用。也就是说,这两个对象的引用次数都是2。在第一种策略中,我们采用标记清除策略的实现,由于函数执行后,这两个对象都离开了作用域,因此这种相互引用不是个问题。而在我们采用引用计数的策略中,当函数执行完毕后,objA 和 objB 还将存在,因为它们的引用次数永远不会为0。如果程序中含有大量类似的函数甚至被反复调用,将会导致大量的内存得不到回收,从而引发严重的内存问题。

为了解决这样的问题,可以将不再使用它们的时候 手动将变量设置为 null ,意味着切断变量与它此前引用的值的连接:

// 不再使用时
objA = null;
objB = null;

这样,当垃圾收集器下次运行的时候,就会删除这些值并回收它们所占用的内存。

性能问题

垃圾收集器是周期性运行的,而且如果变量分配的内存数量很可观,那么回收工作量也会随之变大。这种情况下,确定垃圾收集的时间间隔是非常重要的问题。在IE中,JavaScript 引擎的垃圾收集工作方式为:

  1. 如果垃圾收集例程回收的 内存分配量低于15% ,则变量、字面量和数组元素的 临界值就会被加倍
  2. 如果例程回收了85%的内存分配量,则将各种临界值重置回默认值。

在有些浏览器中可以主动触发垃圾收集过程,如 window.CollectGarbage() 方法会在IE中起作用。但并不建议手动触发。

管理内存

在前面介绍过,一般情况下开发人员不必操心内存管理问题。但存在的一个现象是,JavaScript 程序开发面临一个问题。

现象:分配给 Web 浏览器的可用内存通常要比分配给桌面应用的程序要少。

目的:出于安全考虑,防止运行 JavaScript 的网页耗尽全部系统内存而导致系统崩溃。

需求:确保占用最少的内存可以让页面获得更好的性能。

最佳方式:

解除引用——为执行中的代码只保存必要的数据。一旦数据不再有用,最好通过将其值设置为 null 来释放其引用。

例:

function createPerson(name) {
    var localPerson = new Object();
    localPerson.name = name;
    return localPerson;
}

var globalPerson = createPerson('ZhuXingmin');

// 手动解除引用
globalPerson = null;

注:解除一个值的引用,并不意味着自动回收该值所占用的内存,解除引用的真正作用是让值脱离执行环境,以便于垃圾收集器下次运行时将其回收

小结

JavaScript 是一门具有自动垃圾收集机制的编程语言,开发人员不必关心内存分配问题。垃圾收集例程如下总结:

  • 离开作用域的值将被自动标记为可以回收,因此将在垃圾收集期间被删除。
  • 标记清除是目前主流的垃圾收集算法,思想是给当前不使用的值加上标记,然后再回收其内存。
  • 另一种垃圾收集算法是引用计数,这种算法的思想是跟踪记录所有值被引用的次数。但目前JS引擎都不推荐此算法策略。
  • 当代码中存在循环引用现象时,引用计数算法就会导致问题。
  • 解除变量的引用不仅有助于消除循环引用现象,而且对垃圾收集也有好处。为了确保有效回收内存,应该及时解除不再使用的全局对象、全局对象属性以及循环引用变量的引用。

往期推荐

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-03-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 流眸 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 两种策略
    • 1. 标记清除
      • 2. 引用计数
      • 性能问题
        • 管理内存
        • 小结
        相关产品与服务
        云开发 CloudBase
        云开发(Tencent CloudBase,TCB)是腾讯云提供的云原生一体化开发环境和工具平台,为200万+企业和开发者提供高可用、自动弹性扩缩的后端云服务,可用于云端一体化开发多种端应用(小程序、公众号、Web 应用等),避免了应用开发过程中繁琐的服务器搭建及运维,开发者可以专注于业务逻辑的实现,开发门槛更低,效率更高。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档