首页 > 语言 > JavaScript > 正文

深入理解 JS 垃圾回收

2024-05-06 15:38:38
字体:
来源:转载
供稿:网友

前言

JS之memoization,memoization 的原理是以参数作为 key,函数结果作为 value, 用对象进行缓存起来,以内存空间换 CPU 执行事件。memoization 的潜在陷阱即是严格意义的缓存有着完善的过期策略,而普通对象的键值对并没有。

用闭包进行缓存的对象的内存空间,不会在函数执行完后被清除,在执行量大和参数多样性的情况下,会造成内存占用且得不到释放。

于是,本篇文章就来讲讲 JS 的垃圾回收。

JS 的垃圾回收机制的基本原理是:

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

那我们怎么知道变量是不是在继续使用呢?

首先,局部变量的生存周期是在函数声明和执行阶段,函数执行完毕后,局部变量就没有存在的必要了。全局变量会在浏览器关闭或进程关闭才能释放。

但还有一些场景,比如闭包,通过作用域链访问到函数外部的自由变量,使得自由变量保存在内存中,不会随着函数执行完毕而结束,以及对象的相互引用等,垃圾收集器就没这么容易判断哪个变量有用,哪个变量没用了。

// 经典闭包function closure() {var name = "innerName";return function() {console.log(name);}}var inner = closure();inner(); // innerName;

所以,对于标识无用的变量的策略可能会实现不同,但目前在浏览器中,通常有两种策略:标记清除和引用计数。

二、标记-清除(Mark-Sweep)

从2012年起,所有现代浏览器都使用了标记-清除垃圾回收算法, 那什么叫标记-清除呢?

当变量进入执行环境时,就标记这个变量为“进入环境”。当变量离开环境时,则将其标记为“离开环境”。从逻辑上讲,永远不能释放进入环境的变量所占用的内存,因为只要执行流进入相应的环境,就可能会用到他们。

垃圾收集器在运行的时候会给存储在内存中的所有变量都加上标记。

然后,它会去掉环境中的变量以及被环境中的变量引用的标记。而在此之后再被加上标记的变量将被视为准备删除的变量,原因是环境中的变量已经无法访问到这些变量了。

最后,垃圾收集器完成内存清除工作,销毁那些带标记的值,并回收他们所占用的内存空间。

另外,标记-清除有一个问题,就是在清除之后,内存空间是不连续的,即出现了内存碎片。如果后面需要一个比较大的连续的内存空间时,那将不能满足要求。而标记-整理(Mark-Compact)方法可以有效地解决这个问题。标记阶段没有什么不同,只是标记结束后,标记-整理方法会将活着的对象向内存的一端移动,最后清理掉边界的内存。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表

图片精选