资讯专栏INFORMATION COLUMN

js闭包,垃圾回收,内存泄漏

Jenny_Tong / 2704人阅读

摘要:闭包的本质是将函数内部和函数外部连接起来的一座桥梁。这就可能造成大量内存得不到回收内存泄露,因为它们的引用次数永远不可能是。早期的版本里采用是计数的垃圾回收机制,闭包导致内存泄露的一个原因就是这个算法的一个缺陷。

1.闭包的概念

闭包:指有权访问另一个函数作用域中的变量的函数。
闭包的本质是将函数内部和函数外部连接起来的一座桥梁。

2.如何创建闭包

例1:

function outer(){
    var a=1;
    function inner(){
        a++;
      alert(a);
    }
    return inner;
}
var f1=outer();//创建了一个闭包,f1能访问outer函数中的变量
f1();//弹出2.

这段代码的特点在于:
1.函数inner嵌套在函数outer内部
2.函数outer返回函数inner,并将值赋给了f1
例2:

// 实现累加:方式1
var a = 0;
var add = function(){
    a++;
    console.log(a)
}
add();
add();
//方式2 :闭包
var add = (function(){
    var  a = 0;
    return function(){
        a++;
        console.log(a);
    }
})();
console.log(a); //undefined
add();
add();

//方式2的优点:减少全局变量,将变量私有化
3.闭包与变量的关系

闭包只能取得包含函数中任何变量的最后一个值。
例:

function f1() {
    var res = new Array();
    for(var i=0;i<10;i++){
        res[i] = function() {
            alert(i);
        };
    }
    return res;
}
var f2 = f1();
var f2 = f1();
f2[0]();//alert 10
//并不会返回一次弹出0-9的函数数组,而是弹出10个10的函数数组,因为res中每个函数的作用域中都保存着f1()的活动对象,引用的是同一个变量i,当f1()返回后i的值为10

解决方法:

function f1() {
    var res = new Array();
    for(var i=0;i<10;i++){
        res[i] = (function(num) {
            return function (){
                alert(num);
            }
        })(i);//函数参数按值传递
    }
    return res;
}
var f2 = f1();
var f2 = f1();
f2[0]();//alert 0
4.内存泄露及解决方案

垃圾回收机制

说到内存管理,自然离不开JS中的垃圾回收机制,有两种策略来实现垃圾回收:标记清除 和 引用计数;

标记清除:垃圾收集器在运行的时候会给存储在内存中的所有变量都加上标记,然后,它会去掉环境中的变量的标记和被环境中的变量引用的变量的标记,此后,如果变量再被标记则表示此变量准备被删除。 2008年为止,IE,Firefox,opera,chrome,Safari的javascript都用使用了该方式;

引用计数:跟踪记录每个值被引用的次数,当声明一个变量并将一个引用类型的值赋给该变量时,这个值的引用次数就是1,如果这个值再被赋值给另一个变量,则引用次数加1。相反,如果一个变量脱离了该值的引用,则该值引用次数减1,当次数为0时,就会等待垃圾收集器的回收。

这个方式存在一个比较大的问题就是循环引用,就是说A对象包含一个指向B的指针,对象B也包含一个指向A的引用。 这就可能造成大量内存得不到回收(内存泄露),因为它们的引用次数永远不可能是 0 。早期的IE版本里(ie4-ie6)采用是计数的垃圾回收机制,闭包导致内存泄露的一个原因就是这个算法的一个缺陷。

我们知道,IE中有一部分对象并不是原生额javascript对象,例如,BOM和DOM中的对象就是以COM对象的形式实现的,而COM对象的垃圾回收机制采用的就是引用计数。因此,虽然IE的javascript引擎采用的是标记清除策略,但是访问COM对象依然是基于引用计数的,因此只要在IE中设计COM对象就会存在循环引用的问题!

例子:

window.onload = function(){
    var ele = document.getElementById("id");
    ele.onclick = function(){
        alert(ele.id);
    }
}

这段代码为什么会造成内存泄露?

ele.onclick = function(){
        alert(ele.id);
    }

执行这段代码的时候,将匿名函数对象赋值给ele的onclick属性;然后匿名函数内部又引用了ele对象,存在循环引用,所以不能被回收。

解决方法:

window.onload = function(){
    var ele = document.getElementById("id");
    var id = ele.id; //解除循环引用
    ele.onclick = function(){
        alert(id); 
    }
    ele = null; // 将闭包引用的外部函数中活动对象清除
}
5.总结闭包的优缺点

优点:

当需要一个变量常驻内存时,闭包可以实现一个变量常驻内存 (如果多了就占用内存了)

避免全局变量的污染

私有化变量

缺点:

因为闭包会携带包含它的函数的作用域,因此会比其他函数占用更多的内存

引起内存泄露

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/79029.html

相关文章

  • JS高程中的垃圾回收机制与常见内存泄露的解决方法

    摘要:解决方式是,当我们不使用它们的时候,手动切断链接淘汰把和对象转为了真正的对象,避免了使用这种垃圾收集策略,消除了以下常见的内存泄漏的主要原因。以上参考资料高程垃圾收集类内存泄漏及如何避免内存泄露及解决方案详解类内存泄漏及如何避免 showImg(http://ww1.sinaimg.cn/large/005Y4rCogy1ft1ikzcqzqj30ka0et77a.jpg); 前言 起...

    kidsamong 评论0 收藏0
  • Node.js内存管理和V8垃圾回收机制

    摘要:垃圾回收内存管理实践先通过一个来看看在中进行垃圾回收的过程是怎样的内存泄漏识别在环境里提供了方法用来查看当前进程内存使用情况,单位为字节中保存的进程占用的内存部分,包括代码本身栈堆。 showImg(https://segmentfault.com/img/remote/1460000019894672?w=640&h=426);作者 | 五月君Node.js 技术栈 | https:...

    JowayYoung 评论0 收藏0
  • JS专题之垃圾回收

    摘要:如果没有引用指向该对象零引用,对象将被垃圾回收机制回收。经过增量标记改进后,垃圾回收的最大停顿时间可以减少到原来的左右。解除引用的真正作用是让值脱离执行环境,以便垃圾收集器下次运行时将其回收。 前言 在讲 JS 的垃圾回收(Garbage Collection)之前,我们回顾上一篇《JS专题之memoization》,memoization 的原理是以参数作为 key,函数结果作为 v...

    liujs 评论0 收藏0
  • javascript典型内存泄漏及chrome的排查方法

    摘要:的内存泄漏对于这门语言的使用者来说,大多数的使用者的内存管理意识都不强。内存泄漏的定义指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况。 javascript的内存泄漏 对于JavaScript这门语言的使用者来说,大多数的使用者的内存管理意识都不强。因为JavaScript一直以来都只作为在网页上使用的脚本语言,而网页往往都不会长时间的运行,所以使用者对JavaScript的...

    HackerShell 评论0 收藏0
  • JS中的垃圾回收内存泄漏

    摘要:介绍浏览器的具有自动垃圾回收机制,也就是说,执行环境会负责管理代码执行过程中使用的内存。中的内存泄漏问题程序的内存溢出后,会使某一段函数体永远失效取决于当时的代码运行到哪一个函数,通常表现为程序突然卡死或程序出现异常。 showImg(https://segmentfault.com/img/remote/1460000018932880?w=4400&h=3080); 1. 介绍 浏...

    xiaolinbang 评论0 收藏0
  • 【进阶1-4期】JavaScript深入之带你走进内存机制

    摘要:引擎对堆内存中的对象进行分代管理新生代存活周期较短的对象,如临时变量字符串等。内存泄漏对于持续运行的服务进程,必须及时释放不再用到的内存。 (关注福利,关注本公众号回复[资料]领取优质前端视频,包括Vue、React、Node源码和实战、面试指导) 本周正式开始前端进阶的第一期,本周的主题是调用堆栈,今天是第4天。 本计划一共28期,每期重点攻克一个面试重难点,如果你还不了解本进阶计划...

    不知名网友 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<