一文理清由闭包引起内存泄漏和垃圾回收机制

闭包

  • 闭包的定义:当内部的函数被保存到外部时,将会生成闭包,闭包会致使原有的做用域链不释放,形成内存泄漏。
  • 闭包的好处:
    • 变量长期驻扎在内存中
    • 避免污染全局变量
    • 私有成员的存在
  • 闭包的坏处:
    • 增大内存的使用量
    • 容易形成内存泄漏
  • 闭包的做用/使用场景
    • 实现共有变量 =》 作累加器
      • 代码实现
        function add() {
            var count = 0;
            function demo() {
                count ++;
                console.log(count);
            }
            return demo;
        }
        var counter = add();
        counter();
        counter();
        复制代码
    • 能够作缓存
      • 代码实现
        function eater() {
            var food = '';
            var obj = {
                eat: function() {
                    console.log('i am eating' + ' ' + food);
                    food = '';
                },
                push: function(myFood) {
                    food = myFood;
                }
            }
        }
        var eater1 = eater();
        eater.push('banana');
        eater.eater();
        复制代码
    • 能够实现封装 属性私有化
      • 代码实现
        function Hang(name, wife) {
            var prepareWife = 'xiaozhang';
            this.name = name;
            this.wife = wife;
            this.divorce = function() {
                this.wife = prepareWife;
            }
            this.changePrepareWife = function(target) {
                prepareWife = target;
            }
            this.sayPrepareWife = function() {
                console.log(prepareWife);
            }
        }
        var deng = new Hang('deng', 'xiaoliu');
        deng.prepareWife;
        deng.sayPrepareWife();
        复制代码
  • 闭包的防护
    • 闭包会致使多个执行函数共用一个公有变量,若是不是特殊须要,应该尽可能防止这种状况发生。
  • 解决闭包的方法
    • 使用当即执行函数

当即执行函数

  • 当即执行函数定义:此类函数没有声明,在一次执行事后释放,适合作初始化工做。
  • 当即执行函数和普通函数的区别:当即执行函数执行完就被释放

内存泄漏

  • 内存泄漏定义:应用程序再也不须要占用的时候,因为某些缘由,内存没有被操做系统或可用内存池回收。
  • 内存泄漏的例子:
    • 意外的全局变量
      • 在函数内未声明的变量就赋值,这样会在全局对象建立一个新的变量。
        function bar() {
            say = 'hehe';
        }
        
        即==
        function bar() {
            window.say ='hehe';
        }
        复制代码
      • 或者是使用this建立了全局的变量
        function foo() {
            this.name = 'hehe';
        }
        foo();
        复制代码
    • 被遗忘的计时器或回调函数
      • 使用计时器setInterval()未清除,在老版本的IE6是没法处理循环引用的,会形成内存泄漏。
    • 脱离DOM的引用的
    • 闭包
  • 如何识别的内存泄漏
    • Chrome
      • Timeline
      • Profiles
    • Node
  • 怎么解决
    • 手动释放
      • 代码实现
        var arr = [1, 2, 3];
        arr = null;
        复制代码
    • 使用弱引用(weakset和weakmap)
      • 优势:WeakMap里面对element的引用就是弱引用,不会被计入垃圾回收机制的。也就是说一旦消除对该节点的引用,它的占用内存就会被垃圾回收机制释放。WeakMap保存的这个键值对,也会自动消失。
      • 代码实现
        const vm = new WeakMap();
        const element = document.getElementById('example');
        vm.set(element, 'something');
        vm.get(element);
        复制代码

垃圾回收机制

  • 定义:大多数语言提供自动内存管理,减轻程序员的负担,这就被称为"垃圾回收机制"。
  • 经常使用的垃圾回收算法
    • 引用计数法
      • 优势:
        • 可即刻回收:当被引用数值为0,对象立刻会把本身做为空闲空间连到空闲链表上。也就是说,在变成垃圾的时候就马上被回收。
        • 由于是即便回收,那么程序不会暂停去单独使用很长一段时间的GC,那么最大暂停时间很短。
        • 不用去遍历堆里面的全部活动对象和非活动对象。
      • 缺点:
        • 计数器须要占很大的位置:由于不能预估被引用的上限,打个比方,可能出现32位即2的32次方个对象同时引用一个对象,那么计时器就须要32位。
        • 最大的劣势是没法解决循环引用没法回收的问题,这就是IE以前出现的问题。
      • 代码示例
        var a = new Object();
        var b = a;
        a = null;
        b = null;
        复制代码
    • 标记清除法(在V8引擎使用最多的)
      • 垃圾回收过程
        • 标记阶段:把全部活动对象作上标记
        • 清除阶段:把没有标记(也就是说非活动对象)销毁
      • 优点
        • 实现简单,打标记用一位二进制就能够表示
        • 解决了循环引用的问题
      • 缺点
        • 形成碎片化(有点相似磁盘的碎片化)
        • 再分配时遍历次数多,若是一直没有找到合适的内存块大小,那么会遍历空闲链表(保存堆中全部空闲地址空间的地址造成的链表)一直遍历到尾端。
    • 复制算法
      • 将一块内存空间分为两部分,分别为From空间和To空间。在这两个空间中,一定有一个空间是使用的另外一个空间是空闲的,新分配的对象会被放入From空间中,当From空间被占满的时,新生代GC就会启动了。算法就检查From空间中存活的对象复制到To空间中,若是有失活的对象就会销毁,当赋值完成后将From,空间和To空间互换,这样GC就结束了。

你的点赞是我持续输出的动力 但愿能帮助到你们 互相学习 有任何问题下面留言 必定回复

相关文章
相关标签/搜索