js内存泄漏和垃圾回收机制

内存泄漏

定义


我们知道,程序的运行需要操作系统或者运行时提供内存,而对于持续运行的程序,内存会被持续占用,适时地回收当前不执行的程序占用的内存是很重要的,没有及时地回收内存,轻则造成系统性能变差,重则进程崩溃

那么,什么是内存泄漏呢,简单来说,内存中的某个空间被占用,在应当回收的时间没有被回收,就算是内存泄漏了

有些语言需要自己手动去清除占用内存而又没有在执行的程序,而像JavaScript这类语言有自己的垃圾回收机制,可以对内存进行管理

垃圾回收机制


  1. 标记清除
    垃圾收集器在运行的时候会给存储在内存中的所有变量都加上标记,然后会去掉环境中的变量以及被环境中的变量引用的变量的标记,此后再被标记的变量为将要删除的变量,最后垃圾收集器完成内存清除工作,销毁那些带标记的变量并回收它们的占用空间
  2. 引用计数
    跟踪每个值被引用的次数。如果一个值被赋予一个变量,则引用次数为1,假如这个值被其他变量引用,那么这个引用次数就加一,如果引用这个值的变量引用了别的变量,那么这个值的引用次数就减一。在下次垃圾收集器运行时,引用次数为0的值所占用的内存就会被释放。

但是引用计数会存在一定的问题

function test(){
    var objA = new Object();
    var objB = new Object();

    objA.quoteObj = objB;
    objB.quoteObj = objA;
}

在这个函数中,声明了两个Object对象,而这两个对象又通过属性相互引用,这里的objA和objB的引用次数都变成了2,而且在函数调用完毕后,这两个对象依然存在,即使objA和objB指向了别的值,这里两个new Object()的引用次数仍会为1,永远不会为0,这样就会一直占用内存空间,无法被清除。

虽然有垃圾回收机制,但我们还是需要对一些用到的内存进行处理,利用垃圾回收机制,尽量让没有用到的内存尽快得到释放

几种内存泄漏的情况

1. 意外的全局变量

全局变量所占用的内存,直到页面关闭才会被回收,所以要谨慎使用全局变量

我们知道,如果我们在声明一个变量的时候,没有添加声明符号var,let,const,那么这个变量就会变成一个全局变量,比如下面的函数

function handle(str){
    decoration = '..........';
    return str+decoration
}

在执行完这个函数后,由于这里的decoration变量没有使用声明符,所以在这个函数使用完之后,这个变量所占有的内存本该被回收,却因为变成了全局变量而一直被占用,知道手动清除(赋值为null)或者页面关闭,这就造成了内存泄漏

2. 使用计时器

我们在开发的时候经常会用到setTimeout,setInterval这两个计时器,而这两个计时器在使用时往往很容易引发内存泄漏

第一种泄漏的情况比较常见,如果我们使用计时器,却没有及时地清除计时器,那么计时器的回调函数占用的内存会一直存在,假如当前计时器的回调函数用到了页面的DOM元素,那么在页面销毁的时候,由于定时器占有该页面部分引用,会造成页面的内存无法被正常回收,这样重复地打开关闭这个页面,就会造成内存的不停泄漏

第二种比较少见的情况,在使用定时器的时候,第一个参数传入了字符串,比如下面这样

var t1 = setTimeout((function f1(){
    var d = 1;
}).toString(),0)

这样的定时器,即使使用clearTimeout清除掉,f1还是存在的,此时如果在控制台打印f1的话,会发现它的函数体被打印出来,这说明这里的内存泄漏了

3. 滥用闭包

我们知道,闭包简单来说就是在一个函数内部,引用另一个函数内部的变量,但是这样会使得在当前函数执行完毕后,因为当前函数内部的变量还被另一个函数引用着,所以当前函数所占用的内存无法被回收,这就造成了内存泄漏

4. 被js引用的DOM对象

对于一般的DOM对象来说,如果不再挂载在DOM树上,那么这个对象就应该被回收了,但如果当前有一个js对象指向这个DOM对象的话,就不能回收这块内存

比如下面的结构和js对象

<div id="father">
    <div id="child"></div>
</div>
<script>
    let node = document.getElementById('child')
</script>

如果当前的father div块被删除,一般来说子div占用的内存应该也会被回收,但因为node指向了该DOM对象,所以占用的内存不会被回收,这就造成了内存泄漏
所以如果对某个DOM对象进行了引用,要记得做清除处理

发布了195 篇原创文章 · 获赞 14 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/zemprogram/article/details/104397235
今日推荐