浏览器垃圾与回收机制

浏览器垃圾

在JavaScript中,数据类型分为两类,简单类型和引用类型,对于简单类型,内存是保存在栈(stack)空间中,复杂数据类型,内存是保存在堆(heap)空间中。

  • 基本类型:这些类型在内存中分别占有固定大小的空间,他们的值保存在栈空间,我们通过按值来访问的
  • 引用类型:引用类型,值大小不固定,栈内存中存放地址指向堆内存中的对象。是按引用访问的。

浏览器垃圾:当一个对象(在堆-Heap里)没有任何变量或属性(在栈中)对它进行引用,此时将永远无法操作此对象。

按照V8浏览器的标准,垃圾又分2种类型:

  • 新生代的垃圾:生存时间短的对象(如内部声明的变量,或者块级作用域中的变量等),使用完马上可以回收。
  • 老生代的垃圾:生存时间久的对象(如挂载在windows下面的变量、JS一些API、DOM、闭包等),持久性强,需要等待用完才能回收。

垃圾过多后果: 内存移出,内存泄露.
在这里插入图片描述

垃圾回收机制

垃圾回收是一种自动的内存管理机制。当计算机上的动态内存不再需要时,就应该予以释放。

需要注意的是,自动的意思是浏览器可以自动帮助我们回收内存垃圾,但并不代表我们不用关心内存管理,如果操作不当,JavaScript中仍然会出现内存溢出的情况,造成系统崩溃。

由于字符串,数组,对象等都没有固定大小,因此需要当它们大小已知时,才能对他们进行动态的存储分配。JavaScript程序每次创建字符串,数组或对象时,解释器都必须分配内存来存储那个实体。

JavaScript解释器可以检测到何时程序不在使用一个对象了,当它确定这个对象是无用的时候,他就知道不再需要这个对象了,就可以把它占用的内存释放掉了。

浏览器通常采用的垃圾回收有两种方法:标记清除,引用计数。

垃圾回收器有2种

Major GC( 主垃圾回收器 ):主要负责老生代的垃圾回收;
Minor GC( 副垃圾回收器 ):主要负责新生代的垃圾回收;

在这里插入图片描述

Major GC

负责老生代的垃圾回收,采用了 Mark-Sweep(标记清除) 和 Mark-Compact(标记整理) 算法。

标记清除

首先是标记。
从一组根元素开始,递归遍历这组根元素。
在这个遍历过程中,能到达的元素称为活动对象,没有到达的元素就可以判断为垃圾数据。
然后是垃圾清除。
多次标记-清除后,会产生大量不连续的内存碎片,需要进行内存整理。

老生代的内存中产生了很多内存碎片,若不清理这些内存碎片,如果出现需要分配一个大对象的时候,这时所有的碎片空间都完全无法完成分配,就会提前触发垃圾回收,而这次回收其实不是必要的。

标记整理

为了解决内存碎片问题,Mark-Compact被提出,它是在 Mark-Sweep的基础上演进而来的,相比Mark-Sweep,Mark-Compact添加了活动对象整理阶段,将所有的活动对象往一端移动,移动完成后,直接清理掉边界外的内存。

在这里插入图片描述

Minor GC

负责新生代的垃圾回收,内存占用比较小。
新生代被分为两个区域:一般是对象区域,一半是空闲区域。

新加入的对象都被放入对象区域,等对象区域快满的时候,会执行一次垃圾清理。

先给对象区域所有垃圾做标记。
标记完成后,存活的对象被复制到空闲区域,并且将他们有序的排列一遍。无需碎片整理

在这里插入图片描述
复制完成后,对象区域会和空闲区域进行对调。将空闲区域中存活的对象放入对象区域里。
在这里插入图片描述

因为副垃圾回收器操作比较频繁,所以为了执行效率,一般新生区的空间会被设置得比较小。

一旦检测到空间装满了,就执行垃圾回收。

垃圾回收的时机以及方案

由于垃圾回收是在JS引擎中进行的,而Mark-Compact算法在执行过程中需要移动对象,为了避免JavaScript应用逻辑和垃圾回收器的内存资源竞争导致的不一致性问题,垃圾回收器会将JavaScript应用暂停,这个过程,也被称为全停顿(stop-the-world)

分代收集

一句话总结分代回收就是:将堆分为新生代与老生代,多回收新生代,少回收老生代。这样就减少了每次需遍历的对象,从而减少每次垃圾回收的耗时。
在这里插入图片描述

增量收集

如果脚本中有许多对象,引擎一次性遍历整个对象,会造成一个长时间暂停。

所以引擎将垃圾收集工作分成更小的块,每次处理一部分,多次处理。

这样就解决了长时间停顿的问题。

image.png

闲时收集

垃圾收集器只会在 CPU 空闲时尝试运行,以减少可能对代码执行的影响。

总结

浏览器中不同类型变量的内存都是何时释放?

Javascritp 中类型:值类型,引用类型。

  • 引用类型
    在没有引用之后,通过 V8 自动回收。
  • 值类型
    如果处于闭包的情况下,要等闭包没有引用才会被 V8 回收。
    非闭包的情况下,等待 V8 的新生代切换的时候回收。

闭包会导致内存泄露吗?

内存泄露是指你「用不到」(访问不到)的变量,依然占居着内存空间,不能被再次利用起来。
闭包里面的变量就是我们需要的变量,不能说是内存泄露。

weakMap weakSet 和 Map Set 有什么区别?

在 ES6 中为我们新增了两个数据结构 WeakMap、WeakSet,就是为了解决内存泄漏的问题。
它的键名所引用的对象都是弱引用,就是垃圾回收机制遍历的时候不考虑该引用。
只要所引用的对象的其他引用都被清除,垃圾回收机制就会释放该对象所占用的内存。
也就是说,一旦不再需要,WeakMap 里面的键名对象和所对应的键值对会自动消失,不用手动删除引用。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值