• js内存泄漏


    IE和webkit浏览器都是采用计数来处理垃圾,也就是说每个对象被引用一次,该对象的计数器成员+1,如果计数器为0,那么这个对象被销毁

     例如:

    function A() {
         var obj = {};  
    }

     运行A(); 对象obj在内存中,obj的计数为1,当A()运行完之后,A函数应该被销毁,A函数中的成员对象计数器需要-1,那么obj的计数器成员为0,obj对象被销毁。

    <script>
        var obj;
        function A(){
              obj = $('#id');
              $('#id').p = obj;
        }
    </script>

    $('#id')与obj互相引用,运行A();obj不会被销毁,那么导致$('#id')也不会被销毁,导致内存泄漏。 因为$('#id').p的计数器用户不为0。

    可能发生的场景

    1.1闭包

    看下面代码:

    function assignEvents(){
       var id = "xdi9592";
       document.getElementById("save-btn").onclick = function(event){
          saveDocument(id);
       }
    }

    assignEvents函数为一个DOM元素指定了一个事件句柄,可是事件句柄是一个闭包,可以访问id变量。每次访问时都导致一些性能的损失。

    1.2循环引用(包含dom对象和JS对象循环引用)

      下面代码dom对象和JS对象循环引用导致内存泄漏。

    <html>
        <head>
            <script>
                function myFunction(element){
                    this.elementReference = element;
                    element.expandoProperty = this;
                }
                function Leak(){
                    var obj = new myFunction(document.getElementById("myDiv"));
                }
            </script>
        </head>
        <body onload="Leak()">
        <div id = "myDiv"></div>
        </body>
    </html>

    用谷歌调试器切换到Timeline,查看Memory的记录情况。

    发现调用Leak()函数执行后,内存变大,可能内存已经泄漏。解决内存泄漏有一个办法就是设置对象为null,打破循环引用。

     function Leak(){
          var obj = new myFunction(document.getElementById("myDiv"));
          obj.element = null;
     }

    查看Memory的记录情况:

    内存已经降了下来。

    在nodejs中很多源码都有相互引用的例子,例如nodejs源码lib/_http_server.js

    function connectionListener(socket) {
      // ...
      // 从 parsers 中取一个 parser
      var parser = parsers.alloc();
      parser.reinitialize(HTTPParser.REQUEST);
      //parser和socket相互引用
      parser.socket = socket;
      socket.parser = parser;
      // ...
      state.onData = socketOnData.bind(undefined, this, socket, parser, state);
      // ...
      socket.on('data', state.onData);
      // ...
    }

     v8垃圾回收机制可以分两种,一种是堆回收,一种是栈回收。堆回收才有覆盖的方式即可。栈就比较复杂,一般分成副垃圾回收器和主垃圾回收器;分别处理新生区域内存和老生区域内存。

    副垃圾回收器主要是储存内存小或者不常用的变量。它采用Scavenge 算法, 把栈内存分成对等的两块,一块储存数据,一块不储存,当一块储存数据满之后,把数据copy到另一块内存中,在copy的过程中,去掉碎片和把常用的变量提升到老生区域。

    主垃圾回收器才有计数-整理的方式来清除垃圾,也就是文章开头提到的方式,V8垃圾回收会遍历整个调用栈,看看栈内的引用类型的数据有没有被标记为0,或者没有被引用,则回收。

  • 相关阅读:
    【404】int main(int argc,char * argv[]) windows 下的使用
    【403】COMP9024 Exercise
    【402】Twitter Data Collection
    【401】Python 求合数的所有质数因子
    【400】numpy.pad 为数组加垫(迷宫类题目)
    iOS开发之指纹解锁
    iOS-响应链(Responder Chain)
    iOS上手指点击波纹效果的实现
    使用methodSignatureForSelector与forwardInvocation实现消息转发 (转)
    Objective-C中的@dynamic(转)
  • 原文地址:https://www.cnblogs.com/liuyinlei/p/5366315.html
Copyright © 2020-2023  润新知