开辟的堆内存或者形成的上下文(进栈执行=>栈内存)是越多越好,还是越少越好?
- 肯定是越少越好,因为计算机的内存是固定的,我们所有开辟的内存都在占用计算机的资源,当计算机内消耗存过多,性能也就越来越卡(直接导致我们的产品运行变慢)
思维导图
函数执行就会形成栈内存(从内存中分配的一块空间),如果内存都不销毁释放,很容易就会导致栈内存溢出(内存爆满,电脑就卡死了), => 所以JS中一个重要的性能优化点:减少内存的使用
- =>释放堆内存
- =>释放栈内存(也就是让进栈执行的上下文,尽可能出栈释放)
一、堆内存(HEAP)和 栈内存(STACK)
1、堆内存(HEAP)
堆内存是用来存储引用数据类型值的
- (例如:创建函数和创建对象,就是开辟一个堆内存,把代码字符串或者键值对存储到堆内存中的)
2、栈内存(STACK)
栈内存是用来执行代码和存储基本类型值的(创建的变量也存栈里面了),
- 不仅全局代码执行(EC(G)全局执行上下文),
- 而且函数执行(EC(X)私有上下文),最后也都会进栈执行的
- 基于ES6中的let/const形成的块作用域也是栈内存
二、浏览器常用的垃圾回收机制(内存释放机制):
1、 查找引用方式(weblit内核)
浏览器有自动回收垃圾的机制,定期间隔某段时间,把所有没有被占用的内存回收释放(这种垃圾回收机制,比其它语言要完善一些)
-1).不会销毁的情况:
创建一个堆(16进制地址):
- 如果有变量或者其它东西存储了堆内存的地址,则当前堆内存被视为占用,也就不能释放销毁
上下文进栈执行;
- 如果当前上下文中的某些内容(一般也是当前上下文中创建的堆)被上下文以外的变量或者其它事务所占用,那么当前上下文就不能出栈释放(但是一般情况下,上下文中代码执行完,上下文自己就出栈释放了)
-2).堆内存释放
如果堆内存用完后,我们想去手动释放它,则取消所有的占用:赋值为NULL(NULL是空对象指针,也就是不指向任何的堆内存)
//=>创建一个引用类型值,就会产生一个堆内存
//如果当前创建的堆内存不被其它东西所占用了(浏览器会在空闲的时候,查找每一个内存的引用状况,不被占用的都会给回收释放掉),则会释放
let obj = {
name : 'xiaozhima'
};
let oop = obj;
//此时obj和oop都占用着对象的堆内存,想要释放堆内存,需要手动解除变量和值的关联(null:空对象指针)
obj = null;
oop = null;
复制代码
-3).栈内存释放
栈内存:
- 打开浏览器形成的全局作用域是栈内存
- 手动执行函数形成的私有作用域是栈内存
- 基于ES6中的let/const形成的块作用域也是栈内存
- ……
栈内存销毁:
全局栈内存:关掉页面的时候才会销毁
私有栈内存:
- 1.一般情况下,函数只要执行完成,形成的私有栈内存就会被销毁释放掉(排除出现无限极递归、出现死循环的模式)
- 2.但是一旦栈内存中的某个东西(一般都是堆地址)被私有作用域以外的事物给占用了,则当前私有栈内存不能立即被释放销毁(特点:私有作用域中的私有变量等信息也保留下来了=>这种函数执行形成不能被释放的私有栈内存,也叫做闭包)
function fn(){
//...
}
fn(); //=>函数执行形成栈内存,执行完成栈内存销毁
function X(){
return function(){
//...
}
}
let f=X(); //=>f占用了X执行形成的栈内存中的一个东西(返回小函数对应的堆),则X执行形成的栈内存不能被释放了
复制代码
2、内存计数器方式(Trident内核)
当前内存被其它东西引用了,则给堆计数1(累加计数),取消占用后,则减1,当减到零之后,浏览器就可以把它释放了
三、练习题
1.输出结果
var i = 5;
function fn(i) {
return function (n) {
console.log(n + (++i));
}
}
var f = fn(1);
f(2);
fn(3)(4);
fn(5)(6);
f(7);
console.log(i);
复制代码
2.输出结果
let x = 5;
function fn(x) {
return function(y) {
console.log(y + (++x));
}
}
let f = fn(6);
f(7);
fn(8)(9);
f(10);
console.log(x);
复制代码
3.输出结果
let a=0,
b=0;
function A(a){
A=function(b){
alert(a+b++);
};
alert(a++);
}
A(1);
A(2);
复制代码
4.输出结果
var n=0;
function a(){
var n=10;
function b(){
n++;
console.log(n);
}
b();
return b;
}
var c=a();
c();
console.log(n);
复制代码
5.输出结果
var test = (function(i){
return function(){
alert(i*=2);
}
})(2);
test(5);
复制代码