如何修复此Javascript内存泄漏

时间:2014-09-28 22:45:52

标签: javascript memory-leaks

以下是代码:

function refreshContent(id) {
    function imageLoaded(){
        //get device div
        var device_div = document.getElementById("device-" + id);

            //remove old image, if there is one
        if(device_div.hasChildNodes()) 
            delete device_div.removeChild(device_div.lastChild);

        device_div.appendChild(image);
        var device_id = device_div.id.split("-")[1]; //divs are named "device-<something>"
        window.setTimeout(refreshContent, 5000, device_id);
    }
    var image = new Image();
    image.src = SERVER_BASE_URL + "/api/test/" + id + "/image/" + new Date().getTime();


    image.addEventListener("load", imageLoaded);
}

根据Chrome任务管理器的内存使用率在运行时会迅速增长,而在我禁用它时则不会,因此我知道这部分代码会泄漏。

我有一些想法:

  • 我没有正确删除对旧图像的所有引用,因此孤立的图像对象堆积起来。
  • 对setTimeout的递归调用是将旧函数调用保留在内存中。

我尝试过的任何事情似乎都有所作为。

2 个答案:

答案 0 :(得分:0)

您应该在调用事件侦听器后立即将其删除。

function refreshContent(id) {
    function imageLoaded(){

        image.removeEventListener("load", imageLoaded);

        //get device div
        var device_div = document.getElementById("device-" + id);

            //remove old image, if there is one
        if(device_div.hasChildNodes()) 
            delete device_div.removeChild(device_div.lastChild);

        device_div.appendChild(image);
        var device_id = device_div.id.split("-")[1]; //divs are named "device-<something>"
        window.setTimeout(refreshContent, 5000, device_id);
    }
    var image = new Image();
    image.src = SERVER_BASE_URL + "/api/test/" + id + "/image/" + new Date().getTime();


    image.addEventListener("load", imageLoaded);
}

忘记取消注册事件监听器是导致内存泄漏的常见原因。

答案 1 :(得分:0)

我只是回顾一下我在这里看到的东西。每5秒钟:

  1. 提供了新的id参数
  2. 创建一个新的函数实例(名为imageLoaded),绑定到id
  3. 的值
  4. 创建新图片
  5. 图像绑定到imageLoaded函数实例
  6. 我可能错了,但在我看来,他们会紧紧地握着一个,并且他们可能不会被垃圾收集。

    所以,只需添加一行

    image = null;
    

    image.addEventListener("load", imageLoaded);
    

    可能会解决问题。所以,你最终应该:

    function refreshContent(id) {
      function imageLoaded() {
        //get device div
        var device_div = document.getElementById("device-" + id);
    
        //remove old image, if there is one
        if (device_div.hasChildNodes())
          delete device_div.removeChild(device_div.lastChild);
    
        device_div.appendChild(image);
        var device_id = device_div.id.split("-")[1]; //divs are named "device-<something>"
        window.setTimeout(refreshContent, 5000, device_id);
      }
      var image = new Image();
      image.src = SERVER_BASE_URL + "/api/test/" + id + "/image/" + new Date().getTime();
    
    
      image.addEventListener("load", imageLoaded);
      image = null;
    }
    

    实际上,这是Dispose an image object的副本,但可能是Pascal Le Merrer在答案中有一点意义。