美文网首页
js垃圾回收机制和内存泄露那些事

js垃圾回收机制和内存泄露那些事

作者: 钟钟353251 | 来源:发表于2019-03-14 15:06 被阅读0次

    一、内存垃圾回收的意义:

            在不需要字符串、对象的时候,要释放其所占的内存,否则系统中的内存有限,占用太多会造成系统奔溃。

    二、垃圾回收的机制:

            js会自动回收垃圾内存。

            垃圾回收:找出那些不再继续使用的变量,释放其占用的内存。

            js会按照固定的时间间隔周期性的执行垃圾回收的操作。

            全局变量的的生命周期会知道浏览器关闭结束,也就是说全局变量不会被当成垃圾回收。

    三、怎么回收:标记清除、引用计数

            1) 标记清除  (变量)

                    目前最常用的垃圾回收机制,也是当前浏览器才用的机制。

                    原理:

                    标记清除中有两个重要的概念“进入环境”、“离开环境”。“进入环境”:是变量进入执行环境,“离开环境”:是变量完成任务,离开执行环境。

                    当声明一个变量时,这个变量就是进入的执行环境,浏览器给加“进入环境”的标记,当离开执行环境时,浏览器给它加“离开环境”的标记。并且回收。

                    流程:

                    1. 垃圾收集器在运行的时候给所有内存中的变量打上标记。

                    2. 去掉环境中的变量以及被环境中的变量引用的变量的标记。

                    3. 那些还存在标记的变量则被视为准备删除的变量。

                    4. 最后垃圾收集器会执行清除内存的工作,销毁那些带标记的值并回收他们占用的内存。

            2) 引用计数

                    跟踪记录每个值的引用次数  (值)

                    流程:

                    1. 声明一个变量,并给这个变量赋值,这个值的引用次数就是1

                    2. 同一个值被赋给另一个变量,这个值的引用次数+1

                    3. 变量的值被更改了 那原本那个值的引用次数-1

                    4. 引用次数为0时,说明没办法访问这个值了

                    5. 垃圾收集器下一次运行时,会释放引用次数为0的值所占的内存

                    这个流程潜在一个问题:循环引用,则引用次数不会为0,将不能被自动回收了。

                    循环引用:是指A中包含指向对象B的指针,而对象B中也包含一个指向对象A的引用。

                      Eg.

                           function ftc(){

                               var A = new Object();

                               var B = new Object();

                               A.property = B;

                               B.property = A;

                           }

    四、内存泄露的原因

            js虽然有自动回收机制,但是还是有些情况会造成内存泄漏:

            1. 全局变量不会被自动回收

                    function foo(){

                        this.bar2 = "默认绑定this指向全局"  //全局变量 == window.bsr2

                        bar = "全局变量"  // 没有var声明的变量也是全局变量 == window.bar

                    }

                    foo();

                    解决办法:在函数内使用严格模式or细心一点

                    function foo(){

                        "use strict"

                        this.bar2 = "默认绑定this指向全局"  //全局变量 == window.bsr2

                        bar = "全局变量"  // 没有var声明的变量也是全局变量 == window.bar

                    }

                    foo();

    2. 当不需要setInterval或者setTimeout时,定时器没有被清除。定时器的回调函数以及内部依赖的变量都不能被回收,造成内存泄露。

    var someResource = getData();

    setInterval(function(){

    var node = document.getElementById("id");

    if(node){

    node.innerHTML = JSON.stringify(someResource);

    //定时器也没有被清除

    }

    // node、someResource 存储了大量数据 无法回收

    },1000)

    解决办法:定时器结束时,手动清除定时器。

    3. 循环引用,上文提到。

      解决办法:手动清除变量,释放内存。

    4. 没有清除的DOM元素引用

    var refV = document.getElementById("ID");

    document.body.removeChild(refV);//页面上dom删除了

    console.log(refV);//能输出值。所以虽然在页面上dom删除了,但在js中 这个dom的变量还在 没有被回收

    refV = null;//解决办法 手动清除

    console.log(refV);//可以看到已经被清除了

    5. 闭包引起的内存泄漏:闭包实际上非常容易造成JavaScript对象和DOM对象的隐蔽循环引用

      解决办法:将事件处理函数定义在外部,解除闭包;或者在定义事件处理函数的外部函数中,删除对dom的引用,手动回收。

      Eg.1   

      function ex(){

      var element = document.getElementById("div1");  // 1

      element.onclick = function(){

      console.log("this is event"); // 2

      }

      }

      ex();

      以上函数ex中,用匿名函数创建了一个闭包

      第1处:js对象 element 引用了一个dom对象    JS(element) ----> DOM(div1)

      第2处:dom对象的onclick属性引用了一个匿名函数,这形成一个闭包,这个匿名函数可以引用整个ex内的所有对象,包括element DOM(div1.onclick) ---->JS(element)

      由此形成了JavaScript对象和DOM对象的隐蔽循环引用。

      解决办法:

      function ex(){

      var element = document.getElementById("div1");  // 1

      element.onclick = function(){

      console.log("this is event"); // 2

      }

      element = null; //添加的语句 删除对dom的引用,手动回收

      }

    Eg.2

    function ev(){

    var element = document.getElementById("div2")

    var myName = "lili"

    element.onclick = function(){

    console.log(myName)

    }

    }

    ev();

    由于js中只有函数才具有独立的作用域。

    以上函数ev中,onclick引用的匿名函数去访问myName的时候,发现自身作用域中没有这个myName变量,

    所以需要去访问父作用域中去调用这个myName变量,形成了闭包,所以myName这个变量会一直存在。

    myName这个变量在onclick事件运行之后还会顽固的存在在内存中。

    解决办法是运行完成后手动清除 myName = null

    相关文章

      网友评论

          本文标题:js垃圾回收机制和内存泄露那些事

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