2019年前端面试题-02

作者: Web前端学习营 | 来源:发表于2019-06-10 15:42 被阅读2次

    JS哪些操作会造成内存泄露

    JS的回收机制:

    找出不再使用的变量,然后释放掉其占用的内存,但是这个过程不是实时的,因为其开销比较大,所以垃圾回收系统(GC)会按照固定的时间间隔,周期性的执行。

    垃圾收集器必须跟踪到底哪个变量没用,对于不再有用的变量打上标记,以备将来收回其内存。用于标记的无用变量的策略可能因实现而有所区别,通常情况下有两种实现方式:“标记清除”和“引用计数”。引用计数不太常用,标记清除较为常用。

    1、标记清除

    这是javascript中最常用的垃圾回收方式。当变量进入执行环境是,就标记这个变量为“进入环境”。从逻辑上讲,永远不能释放进入环境的变量所占用的内存,因为只要执行流进入相应的环境,就可能会用到他们。当变量离开环境时,则将其标记为“离开环境”。

    垃圾收集器在运行的时候会给存储在内存中的所有变量都加上标记。然后,它会去掉环境中的变量以及被环境中的变量引用的标记。而在此之后再被加上标记的变量将被视为准备删除的变量,原因是环境中的变量已经无法访问到这些变量了。最后。垃圾收集器完成内存清除工作,销毁那些带标记的值,并回收他们所占用的内存空间。

    *关于这一块,建议读读 ,关于作用域链的一些知识详解,读完差不多就知道了,哪些变量会被做标记。

    functiontest(){vara=10;//被标记,进入环境varb=20;//被标记,进入环境}test();//执行完毕之后a、b又被标记离开环境,被回收

    2、引用计数

    另一种不太常见的垃圾回收策略是引用计数。引用计数的含义是跟踪记录每个值被引用的次数。当声明了一个变量并将一个引用类型赋值给该变量时,则这个值的引用次数就是1。相反,如果包含对这个值引用的变量又取得了另外一个值,则这个值的引用次数就减1。当这个引用次数变成0时,则说明没有办法再访问这个值了,因而就可以将其所占的内存空间给收回来。这样,垃圾收集器下次再运行时,它就会释放那些引用次数为0的值所占的内存。

    functiontest(){

      var a={};//a的引用次数为0varb=a;//a的引用次数加1,为1varc=a;//a的引用次数加1,为2varb={};//a的引用次数减1,为1}

    哪些操作会造成内存泄露:

    1.意外的全局变量引起的内存泄露,一个未声明变量的引用会在全局对象中创建一个新的变量。在浏览器的环境下,全局对象就是 window,也就是说:

    functionfoo(arg){    bar ="aaaaa";}// 实际上等价于functionfoo(arg){window.bar ="aaaaa";}// 类似的functionfoo(){this.variable ="qqqqq";}//this 指向全局对象(window)foo();

    2.闭包引起的内存泄露

    functionfn1(){varn=1;functionfn2(){//在加一个fn2当他的子集alert(n);    }returnfn2();//return出来后 他就给 window了所以一直存在内存中。因为一直在内存中,在IE里容易造成内存泄漏}fn1();

    3.dom清空或删除时,事件未清除导致的内存泄漏

    varelements={button:document.getElementById("button"),image:document.getElementById("image"),text:document.getElementById("text")};functiondoStuff(){    image.src="http://some.url/image";    button.click():console.log(text.innerHTML)}functionremoveButton(){document.body.removeChild(document.getElementById('button'))}

    4.循环引用

    functionleakMemory(){varel =document.getElementById('el');varo = {'el': el };    el.o = o;}

    5.定时器setTimeout和setInterval:当不需要setInterval或者setTimeout时,定时器没有被clear,定时器的回调函数以及内部依赖的变量都不能被回收,造成内存泄漏。比如:vue使用了定时器,需要在beforeDestroy 中做对应销毁处理。js也是一样的。

    clearTimeout(***)clearInterval(***)

    6.如果在mounted/created 钩子中使用了$on,需要在beforeDestroy 中做对应解绑($off)处理

    beforeDestroy() {  this.bus.$off('****');}

    7.死循环

    while(1){    a++;}

    8.给DOM对象添加的属性是一个对象的引用

    vartestObject ={};document.getElementById('idname').property= testObject;//如果DOM不被消除,则testObject会一直存在,造成内存泄漏

    相关文章

      网友评论

        本文标题:2019年前端面试题-02

        本文链接:https://www.haomeiwen.com/subject/oobzxctx.html