JS闭包
闭包的定义
展开
MDN中对于JS闭包的解释:

词法环境即为函数定义时所在的作用域,也可以理解为VO。即一个函数,如果可以访问外部作用域的变量,那么该函数和周围环境的组合就是闭包。
从该定义来看,JS中的函数都具有闭包的特性,都可以称之为闭包。但从严格意义来讲,JS中的一个函数,如果访问了外层作用域的变量,那它就是一个闭包。
闭包导致的内存泄露
展开
以如下代码为例:
1 | function foo(){ |
bar函数与变量a形成了闭包,且通过bar引用了foo函数返回bar函数,在GO中存在bar对foo函数返回bar函数对象的引用,bar函数对象的[[Scopes]]
属性又存在对foo函数的AO的引用,根据垃圾回收机制中标记清除算法的处理,bar变量即使以后未被调用,bar函数和foo函数的AO所占据的内存也不会被回收,就造成了内存泄漏。
所以,对于闭包的内存泄漏,其实就是引用链中的对象无法被释放。
解决方法:
手动进行bar = null
,手动释放对对象的引用。
常见的垃圾回收机制(GC)算法
展开
垃圾回收机制(Garbage Collection)简称GC。
对于那些不再使用的对象,我们称之为垃圾,它需要被回收以释放更多的内存空间。
在JS中,内存管理是自动的、无形的,就是由于GC的存在帮我们自动管理内存。
常见的GC算法有:
-
引用计数法
- 每当存在对象的引用时,相应对象引用计数加1,当引用计数为0时,该对象被回收。
- 但容易产生循环引用,即两个对象的属性进行相互引用,形成环形链表,导致内存泄漏(两个引用对象的变量赋值为null,但其属性仍然存在引用,导致对象中的引用计数不为0)。
-
标记清除法
- 核心思路为可达性。
- 需要设置一个根对象(root object),在浏览器中为window,垃圾回收器会定时从根对象出发,找所有从根对象开始有引用的对象,对于没有引用的对象,就认为是不可用的对象,就会被垃圾回收其处理。
-
标记整理法
- 在标记清除法类似,不同的是,在回收的同时会将保留的对象搬运到连续的内存空间中,整合空闲空间,避免碎片化。
-
分代收集法
-
增量收集法
- 将回收分为几部处理,减少垃圾回收的延迟。
-
闲时收集法
- 在CPU空闲的时候进行回收。