JavaScript 垃圾收集

JavaScript具有自动垃圾收集机制,也就是说,执行环境会负责管理执行过程中使用的内存。这种垃圾收集机制的原理其实很简单:找出那些不再继续使用的变量,然后释放其占用的内存。为此,垃圾收集器会按照固定的时间间隔周期性地执行这一操作。

一、什么是垃圾

一般来说没有被引用的对象就是垃圾,就是要被清除,有个例外如果几个对象引用形成一个环,互相引用,但根访问不到它们,这几个对象也是垃圾,也要被清除。

二、垃圾收集方式

标记清除

JavaScript中最常用的垃圾收集方式是标记清除。

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

可以使用任何方式来标记变量,如何标记变量其实并不重要,关键在于采取什么策略。
总结一下,我们可以用“可达性”的概念来确定某个对象是否应该被回收:如果一个对象从全局执行环境可达,则说明它可以被访问到,不应该被回收;如果一个对象或一组相互引用的对象无法从全局执行环境可达,说明已经无法引用该对象,则需要对其回收并释放内存。
举个例子:

以上是一幅对象之间的引用图,如果我们执行以下代码:

delete family.father;
delete family.mother.husband;

则名为John的对象将变得不可访问,垃圾收集器在下次运行时将会对其回收。需要注意的是,为了让系统回收John对象,以上两行代码缺一不可,因为如果只切断一个引用,还可以通过另一种方式引用到它,那么它依然是可访问/可达的,不应对其回收。这里判断可达性是依据传入的引用,与传出的引用无关,即虽然John可以通过 .wife访问到Ann,但是它本身已经变得不可访问。
以上是针对对象层面来说的,具体到函数中的局部变量,根据函数中局部变量生命周期的概念,我们知道局部变量只在函数执行的过程中存在。在函数的执行过程中,会为局部变量在栈(或堆)内存上分配相应的空间,以便存储它们的值。然后在函数中使用这些变量,直至函数执行结束。此时,局部变量就没有存在的必要了,因此可以释放它们的内存以供将来使用。

引用计数

另一种不太常见的垃圾收集策略叫做引用计数。
引用计数的含义是跟踪记录每个值被引用的次数。当声明了一个变量并将一个引用类型值赋给该变量时,则这个值的引用次数就是1。如果同一个值又被赋给另一个变量,则该值的引用次数加1。相反,如果包含对这个值引用的变量又取得了另外一个值,则这个值的引用次数减1。当这个值的引用次数变成0时,则说明没有办法再访问这个值了,因而就可以将其占用的内存空间回收回来。这样,当垃圾收集器下次再运行时,它就会释放那些引用次数为零的值所占用的内存。
但是这种策略在遇到循环引用时会遇到问题,如果两个对象互相引用,那么它们的引用次数永远不会变成0,如果这两个对象是局部变量,在函数运行完毕后本该释放内存却得不到释放,或者其被切断了与全局执行环境的联系从而变得不可访问,但是由于其引用次数不为0得不到释放从而导致内存泄漏。

三、管理内存

JavaScript引擎应用了许多优化,使其运行得更快,并且不影响执行。

一些优化:

  • 分代回收——对象分为两组:“新对象”和“旧对象”。许多对象出现,完成它们的工作并迅速结束 ,它们很快就会被清理干净。那些活得足够久的对象,会变“老”,并且很少接受检查。
  • 增量回收——如果有很多对象,并且我们试图一次遍历并标记整个对象集,那么可能会花费一些时间,并在执行中会有一定的延迟。因此,引擎试图将垃圾回收分解为多个部分。然后,各个部分分别执行。这需要额外的标记来跟踪变化,这样有很多微小的延迟,而不是很大的延迟。
  • 空闲时间收集——垃圾回收器只在 CPU 空闲时运行,以减少对执行的可能影响。

除了浏览器自动做的以上工作以外,作为JavaScript开发人员,虽然我们一般不必操心内存管理的问题,但我们也要有内存管理的思想,一些好的编程习惯会优化内存占用从而可以让页面获得更好的性能。
比如:
一旦数据不再有用,最好通过将其值设置为null来释放其引用----这个做法叫做解除引用。这一做法适合于大多数全局变量和全局对象的属性。不过要知道的是,解除一个值的引用并不意味着自动回收该值所占用的内存。解除引用的真正作用是让值脱离执行环境,以便垃圾收集器下次运行时将其回收。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值