闭包定义
有权访问另一个函数作用域中变量的函数
- 闭包函数
function fa() {
var a = 1;
return function () {
console.log(a)
a++
}
}
var o = fa();
o(); // 1
o(); // 2
闭包内存泄漏
- 什么叫内存泄漏
程序运行就需要内存
持续运行的服务进程,必须及时释放不再用到的内存,
不然内存越战越高,轻则影响系统性能,重则导致程序崩溃
- 内存泄漏情况
1 意外的全局变量
2 闭包引起(为了维护函数内部的局部变量,使其不得释放)
3 未被清理的DOM
4 被遗忘的定时器,或者回调 // ?
- 内存泄漏案例
function leaks(){
leak = 'xxxxxx'; // leak 成为一个全局变量,不会被回收
}
function fa() { // 闭包
var a = 1;
return function () {
console.log(a)
a++
}
}
var obj1 = {};
var obj2 = [};
obj1.a = obj2;
obj2.b = obj1; // 相互引用,即使不在使用也清除不掉
btn.click = () => {
var div = document.getElementById('box');
div.onclick = function(){
.....
};
- 垃圾回收机制V8
1 标记清除
2 引用计数
js新生成一个对象(比如函数),就会在堆内存中消耗一块内存。代码中可能有很多个变量会指向这个对象,js会跟踪这些指针,当最后一个指针不再指向这个对象时,那么这个对象占用的内存就会被释放
闭包如何导致内存泄漏的?
- 先了解,执行环境
执行环境:
定义了变量和函数的有权访问权限,环境中定义的变量和函数都保存在这个对象中(函数是对象
放在堆内存中),函数执行完毕,环境被销毁,变量和函数定义也被销毁
全局环境,程序退出才会被销毁
- 作用域链
代码在执行环境中,他能够访问到的变量和函数,以及其访问顺序(先局部,然后再全局)
- 看案例代码
function test() {
var str = "hello";
return function () {
console.log(str)
}
}
var o = fa();
o();
- 代码分析
在堆上有两个对象
对象1: ‘hello'
对象2: function(){console.log(a)}
var str = 'hello' // 对象1被引用一次,计数1
function(){console.log()} // 这里再次引用对象1,计数 1+1 = 2
fa()执行完毕 :
// 保存在其中的变量var str 被销毁,所以这个时候,对象1的引用次数2-1=1
o()执行完毕后,对象1的引用次数还是1,所以他不会被GC回收
而且:这里o对对象2引用了一次,执行完o()后,并没有o=null,清除对对象2的引用