GC浏览器的垃圾回收机制(内存释放机制)
栈内存释放
- 加载页面,形成一个全局上下文,只有页面关闭后,全局上下文才会被释放
- 函数执行会形成一个私有上下文,进栈执行,当函数中代码执行完成,大部分情况下,形成的私有上下文会被出栈释放掉,以此优化内存大小
- 特殊情况:如果当前上下文中开辟的某个“堆内存”被当前上下文以外的变量或其他事物所占用,此时当前上下文是不能被释放的
堆内存释放
- 查找引用:如chrome浏览器。浏览器在空闲或者指定时间内,查看所有的堆内存,把没有被任何东西占用的堆内存释放掉,而被占用的是不会被释放的。
- 引用计数:如IE浏览器。创建的堆内存,被占用一次浏览器的计数就+1,取消占用计数就-1,当记录的数字为0时,内存就会被释放掉;在某些情况下可能会导致计数混乱从而导致内存泄漏
闭包
函数执行,会形成一个私有的上下文,私有上下文里面的私有变量会受到私有上下文的“保护”,不受外界干扰,同时有可能形成不被释放的上下文(如果上下文中的某些内容(一般指的是堆内存地址)被当前上下文以外的其它事物(如:变量/事件绑定等)所占用,则当前上下文不能被出栈释放),里面的私有变量和一些值就会被“保存”起来,这些值可以供其“下级”上下文调取使用。我们把函数这种“保存/保护”机制称为闭包。
- 保护:保护私有上下文中的私有变量不受外界干扰
- 保存:当前上下文不被释放,则当前上下文中的私有变量和值会被保存。
- 弊端:如果大量使用闭包,会导致栈内存不断增大,页面渲染变慢,影响程序性能;所以应该合理使用闭包。
- 闭包案例
function fn(){
var x = 100;
return fucntion(){
console.log('形成闭包');
}
}
var f = fn();
f();
- 案例解析
- 首先还是先开辟一块栈内存(ECStack)用来供代码执行
- 然后形成全局上下文,并进栈执行,创建函数fn(0x001)、执行函数fn并将返回值赋值给变量f,最后调用函数f
- 函数fn执行时会形成一个私有上下文EC(FN)和私有变量对象AO。在私有上下文中声明变量x赋值100,然后创建一个函数并将函数地址返回。 由于在当前上下文中所创建的函数(0x0001)被全局上下文中的变量f所占用,所以即使fn函数执行完成,该函数的私有上下文及其私有变量也不会被释放。
- 在函数f执行的时候,又会形成一个私有上下文,该函数所 产生的私有上下文没有被其它变量所占用,所以当该函数执行完成后,会立即释放掉。
一图解真相