前言
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)方法可以有效地解决这个问题。标记阶段没有什么不同,只是标记结束后,标记-整理方法会将活着的对象向内存的一端移动,最后清理掉边界的内存。
新闻热点
疑难解答
图片精选