• js中的内存泄漏


    概述

    之前虽然知道函数作用域, 上下文, 作用域链, 闭包, 引用清除与标记清除等概念, 但是总觉得既然有标记清除, js就不怎么会发生内存泄漏. 今天查了下资料, 梳理了一下, 记录下来供以后开发时参考, 相信对其他人也有用.

    全局变量

    function foo(arg) {
    bar = "this is a hidden global variable";
    }
    

    如上代码, 声明了一个全局变量, 它不会被自动回收, 所以会造成内存泄漏. 需要手动回收, 改成如下所示:

    方法一(推荐)
    function foo(arg) {
    var bar = "this is a hidden global variable";
    }
    
    方法二
    function foo(arg) {
    bar = "this is a hidden global variable";
    // Do something;
    bar = null;
    }
    

    计时器

    var someResource = getData();
    setInterval(function() {
        var node = document.getElementById('Node');
        if(node) {
        // Do stuff with node and someResource.
        node.innerHTML = JSON.stringify(someResource));
        }
    }, 1000);
    

    上面的计时器不断的执行函数, 在执行的时候会调用外面的变量someResource, 所以someResource一直在内存中无法被释放. 要修正这种内存泄漏只能设置一个计时器的停止条件了.

    var someResource = getData();
    setInterval(function() {
        var node = document.getElementById('Node');
        if(node) {
        // Do stuff with node and someResource.
        node.innerHTML = JSON.stringify(someResource));
        }
    }, 1000);
    if(timesRun === 60){
    clearInterval(interval);
    }
    

    dom相关操作

    <div id="container">  
    </div>
    
    $('#container').bind('click', function(){
        console.log('click');
    }).remove();
    

    上面删除了dom但是没有删除绑定的事件, 也会造成内存泄漏. 解决方法是先把事件清除再remove.

    <div id="container">  
    </div>
    
    $('#container').bind('click', function(){
        console.log('click');
    }).off('click').remove();
    

    闭包

    var leaks = (function(){
        var leak = 'xxxxxx';// 被闭包所引用,不会被回收
        return function(){
            console.log(leak);
        }
    })()
    leaks();
    

    上面的leak被闭包所引用, 所以不会被回收.解决方法是在执行操作之后释放掉内存.

    var leaks = (function(){
        var leak = 'xxxxxx';// 被闭包所引用,不会被回收
        return function(){
            console.log(leak);
            leak = null;
        }
    })()
    leaks();
    

    不被注意的内存泄漏

    有一种内存泄漏很常见, 但是不是那么明显, 代码如下:

    window.onload=function outerFunction(){
        var obj = document.getElementById("element");
        obj.onclick=function innerFunction(){};
    };
    

    这是一个很常见也用的较多的事件绑定代码, 它实际上是闭包引起的内存泄漏问题. 首先我们在内层函数中声明了一个变量obj, 然后我们给obj绑定了一个click事件, 这个click事件被外层window引用, 导致innerFunction()函数形成了一个闭包, 虽然这个函数里面没有任何表达式, 但是其中的this指向了obj, 所以obj在代码执行结束之后并不会被清除, 需要手动释放.修改方法如下:

    方法一(推荐):
    window.onload=function outerFunction(){
        var obj = document.getElementById("element");
        obj.onclick=function innerFunction(){};
        obj = null;
    };
    
    方法二(不推荐):
    function innerFunction(){};
    window.onload=function outerFunction(){
        var obj = document.getElementById("element");
        obj.onclick=innerFunction;
        obj = null;
    };
    

    值得注意的是, jQuery封装了解决这种内存泄漏的方法, 它的原理是使用jQuery缓存来绑定事件, 所以存下下面的方法三. 但是为了保险起见, 还是建议使用方法一手动清除声明的变量.

    window.onload=function outerFunction(){
      var obj = document.getElementById("element");
      $(obj).click(function innerFunction(){});
    };
    

    查看内存泄漏

    使用chrome能够很方便的查看网页的内存使用情况, 操作如下:

    1. 打开开发者工具,选择 Network 右边的 Timeline 面板
    2. 在顶部的Capture字段里面勾选 Memory
    3. 点击左上角的录制按钮。
    4. 在页面上进行各种操作,模拟用户的使用情况。
    5. 一段时间后,点击对话框的 stop 按钮,面板上就会显示这段时间的内存占用情况。
  • 相关阅读:
    【Alpha版本】 第六天 11.14
    HashMap(JDK8) 源码分析及夺命9连问
    JUC基础
    快乐的一天从AC开始 | 20210804 | CF1549C
    快乐的一天从AC开始 | 20210803 | P3482
    快乐的一天从AC开始 | 20210802 | P2034
    快乐的一天从AC开始 | 20210801 | P1988
    快乐的一天从AC开始 | 20210731 | P2825
    快乐的一天从AC开始 | 20210730 | P4656
    快乐的一天从AC开始 | 20210729 | P5346
  • 原文地址:https://www.cnblogs.com/yangzhou33/p/8711935.html
Copyright © 2020-2023  润新知