代码之家  ›  专栏  ›  技术社区  ›  JoshNaro

有人能解释为什么这个JavaScript会导致IE7内存泄漏吗?

  •  2
  • JoshNaro  · 技术社区  · 17 年前

    代码相当长,但很简单:

    • 创建了100个泄漏的JavaScript对象。
    • 从JS对象创建10个泄漏元素。
    • 1个元素被删除,1个元素被添加10000次。

    我认为 detachEvent 呼叫功能不正常。 还有,如果你改变 this.eventParams

        <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>Memory Leak With Fix</title>
        <style type="text/css">
          .leakyEle 
          {
            border: solid 1px red;
            background-color: Gray;
          }
        </style>
        <script type="text/javascript">
        
    /******************************* MAIN ********************************/
    var leakObjArray = new Array();
    AddEvent(window, 'load', Startup, false);
    
    function Startup() {           
      for(var i=0; i<100; i++) {
        leakObjArray.push(new LeakyObj(i));
      }
      
      for(var j=0; j<10; j++) {
        leakObjArray[j].CreateLeakyEle();
      }     
      var container = document.getElementById('Container');
      AddEvent(container, 'click', Run, false);
      alert('Close this dialog and click the document to continue.');
    }
    
    function Run() {
      var k = 0;
      var l = 10;
      
      for(var m = 0; m<10000; m++) {
        leakObjArray[k].DestroyLeakyEle();
        leakObjArray[l].CreateLeakyEle();
        if(k<leakObjArray.length - 1) {
          k++;
        } else {
          k = 0;
        }
        if(l<leakObjArray.length - 1) {
          l++;
        } else {
          l = 0;
        }
      }   
      for(var i=0; i<leakObjArray.length; i++) {
        leakObjArray[i].DestroyLeakyEle();
      }
      alert('Test Complete.');
    }
    
    /******************************* END MAIN ********************************/
    
    /******************************* LEAKY OBJECT ********************************/
    function LeakyObj(id) {
      this.id = id;
      this.leakyEle = null;
      this.containerEle = document.getElementById('Container');
      this.clicked = false;
      this.eventParams = new Array();
    }
    
    LeakyObj.prototype.CreateLeakyEle = function() {
      var leakyEle = document.createElement('div');
      leakyEle.id = 'leakyEle' + this.id;  
      leakyEle.className = 'leakyEle';           
      leakyEle.innerHTML = this.id + ' --- XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' +
        '<br/>XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' +
        '<br/>XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' +
        '<br/>XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' +
        '<br/>XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
       
      this.leakyEle = leakyEle;
      
      var _self = this;
      this.eventParams.push(AddEventWithReturnParams(this.leakyEle, 'click', function() { _self.EventHandler(); }, false));
      
      this.containerEle.appendChild(leakyEle);
    }
    
    LeakyObj.prototype.DestroyLeakyEle = function() {
      if(this.leakyEle != null) {
        this.containerEle.removeChild(this.leakyEle);
        for(var i=0; i<this.eventParams.length; i++) {      
          RemoveEventOverload(this.eventParams[i]);
        }
        this.leakyEle = null;
      }
    }
    
    LeakyObj.prototype.EventHandler = function() {
      this.leakyEle.style.display = 'none';
      this.clicked = true;
    }
    
    /******************************* END LEAKY OBJECT ********************************/
    
    /******************************* GENERAL FUNCS ********************************/
        
    function AddEvent(elm, evType, fn, useCapture){
      var success = false;
      if(elm.addEventListener) {
        if(evType == 'mousewheel') evType = 'DOMMouseScroll';
        elm.addEventListener(evType, fn, useCapture);    
        success = true;
      } else if(elm.attachEvent) {
        if(evType == 'mousewheel') {
          window.onmousewheel = document.onmousewheel = fn;
          success = true;
        } else {
          var r = elm.attachEvent('on' + evType, fn);
          success = r;
        }
      } else {
        success = false;
      }
      elm = null;
      return success;
    }
    
    function AddEventWithReturnParams(elm, evType, fn, useCapture) {
      var eventParams = new EventParams(elm, evType, fn, useCapture);
      AddEvent(elm, evType, fn, useCapture);
      return eventParams;
    }
    
    function RemoveEvent(elm, evType, fn, useCapture) {
      if(elm) {  
      if(elm.removeEventListener) {
        elm.removeEventListener(evType, fn, useCapture);    
        return true;
      } else if(elm.detachEvent) {  
        var r = elm.detachEvent('on' + evType, fn);    
        return r;
      } else {
        debugger;
      }  
      }
    }
    
    function RemoveEventOverload(eventParams) {
      if(eventParams) {
        return RemoveEvent(eventParams.element, eventParams.eventType, eventParams.handler, eventParams.capture);
      }
    }
    
    function EventParams(elm, evType, fn, useCapture) {
      return {
        element: elm,
        eventType: evType,
        handler: fn,
        capture: useCapture
      }
    }
    /******************************* END GENERAL FUNCS ********************************/
        </script>
    </head>
    <body>
    <div id="Container"></div>
    </body>
    </html>
    
    2 回复  |  直到 5 年前
        1
  •  4
  •   Douglas Mayle    17 年前

    如果查看代码,您应该注意到,在eventParams数组中存储的每个eventParams对象中,您都有对这些对象的引用,但您从未清空数组。尝试清除你的阵列。。。

        2
  •  2
  •   Lee Kowalkowski    17 年前

    看起来您正在将内容推送到CreateLeakyEle内的eventParams数组上,但从未删除它?是这样吗?