随着前端的蓬勃发展,JS可实现的功能越来越多,也越来越复杂,尤其是在大型前端项目中,几十或上百个大大小小的产品功能。如何让前端性能最优,用户体验更高,是摆在前端开发者面前不可避免的问题,而JS的内存泄露就是其中一个提升前端性能的场景。
JS GC(垃圾回收)机制
说到内存泄露问题,我们必须得了解JS GC(Garbage Collection 垃圾回收)机制。在JS中我们声明的各种变量,如对象、函数、普通数值等,都是存储在内存中的。如果在使用完成后,不进行销毁,会持续占用浏览器的内存。就像电脑的内存占用升高,会导致电脑越来越卡顿,同理,浏览器的内存占用越来越高,就会导致浏览器越来越卡顿,用户的体验就会降低。
在JS中,是有自动GC(垃圾回收)机制的,当一个变量“无用”
时就会被系统回收掉,从内存中释放。
JS的垃圾回收器会周期性的找出不再使用的变量,释放其所占用的内存。
当一个变量“无用”即生命周期结束了,
GC策略 - 引用计数法
先定个调子,引用计数法是一种古老的已“被抛弃”的GC策略。
引用计数法,是指专门对引用类型数据变量进行计数统计:
- 声明一个引用类型的值,赋值给一个
变量A
,这个引用计数+1; - 如果这个引用类型值又赋值给了别的
变量B
,则计数再次+1; - 当值为引用类型值的
变量A
赋值为了其他值,则计数-1
当该引用类型值的引用计数次数为0时,触发GC,内存释放。
代码来演示下这个过程。
// 定义对象,此时引用类型值存储在内存中,计数+1,引用次数总值为1
let A = {
name: '引用计数'
}
// 引用类型值又赋值给了B,计数+1,引用次数总值为2
let B = A;
// 变量A赋值为了其他值,{name: '引用计数'}这个引用值计数-1,引用次数总值为1
A = null;
// 变量B赋值为了其他值,{name: '引用计数'}这个引用值计数-1,引用次数总值为0
B = null;
// 当{name: '引用计数'}这个引用类型值被引用次数为0时,触发GC机制,所占用的内存被释放
But,但是,这里是要一个转折线的~~~~
引用计数策略有一个缺陷就是,当存在循环引用时,引用计数策略就失效了,导致变量内存无法被销毁。
// 定义函数
function printAB () {
const A = {
name: 'A'
}
const B = {
name: 'B'
}
// 相互引用
A.b = B;
B.a = A;
}
// 调用函数
printAB();
在函数调用完毕后,全局