前端问题——内存泄漏

内存泄漏

内存泄漏指的是一块被分配的内存既不能使用,又不能回收,直到浏览器进程结束。

JS 的垃圾回收机制:垃圾回收机制很简单那,找出不再使用的变量,然后释放掉其占用的内存,但是这个过程不是实时的,因此其开销比较大,所以垃圾回收系统(GC)会按照固定的时间间隔,周期性的执行。

到底哪些变量是没有用?所以垃圾回收器必须跟踪到底哪些变量有没有使用,对于不再用的变量打上标记,以备将来回收其内存。用于标记的无用的变量的策略可能因实现而又所区别,通常情况下有两种实现方式:标记清除和引用计数。引用计数不太常用,标记清除较为常用。

标记清除
当变量进入环境时,例如,在函数中声明一个变量,就将这个变量标记为“进入环境”。从逻辑上讲,永远不能释放进入环境的变量所占用的内存,因为只要执行流进入响应的环境,就可能用到它们。而当变量离开环境时,则将其标记离开环境。

function test(){
  var a=10;//被标记,进入环境
  var b=20;//被标记,进入环境
}
test();//执行完毕之后a、b又被标记离开环境,被回收

** 引用计数**
就是跟踪记录每个值被引用的次数。当声明了一个变量并将一个引用类型值赋给该变量,则这个值的引用次数就是1.如果同一个变量又被赋给另一个变量,则该值的引用次数加1。相反,如果包含对这个值引用的变量又取得另外一个值,则这个值的引用次数减1.当这个值的引用次数变成0时,则说明没有办法再访问这个值了,因而就可以将其占用的内存空间回收回来。这样,当垃圾回收器下次再运行时,就会释放哪些次数为0的值所占用的内存。

function test(){
  var a={};  //a的引用次数为0
  var b=a;   //a的引用次数加1,为1
  var c=a;   //a的引用次数加1,为2
  var b={};  //a的引用次数减1,为1
}

哪些会造成内存泄漏:

  1. 意外的的全局变量引起的内存泄漏 注意:局部变量不用时,没有设为null。不会引起内存泄漏。
function leak(){
  leak="xxx";//leak成为一个全局变量,不会被回收
}
  1. 闭包引起的内存泄漏
function bindEvent(){
  var obj=document.createElement("XXX");
  obj.οnclick=function(){
    //Even if it's a empty function
  }
}

闭包可以维持函数内部局部变量,使其得不到释放。上述定义事件回调时,由于函数内定义函数,并且内部函数——事件回调的引用外暴了,形成了闭包。
解决方法:
① 将事件处理函数定义在外部,解除闭包。

       function onclickHandler(){
          //do something
        }
        function bindEvent(){
          var obj=document.createElement("XXX");
          obj.οnclick=onclickHandler;
        }

② 在定义事件处理函数的外部函数中,删除对DOM的引用。

        function bindEvent(){
          var obj=document.createElement("XXX");
          obj.οnclick=function(){
            //Even if it's a empty function
          }
          obj=null;
        }
  1. 没有清理的DOM元素引用:
var elements={
    button: document.getElementById("button"),
    image: document.getElementById("image"),
    text: document.getElementById("text")
};
function doStuff(){
    image.src="http://some.url/image";
    button.click():
    console.log(text.innerHTML)
}
function removeButton(){
    document.body.removeChild(document.getElementById('button'))
}
  1. 被遗忘的定时器或者回调

var someResouce=getData();
setInterval(function(){
var node=document.getElementById(‘Node’);
if(node){
node.innerHTML=JSON.stringify(someResouce)
}
},1000)

id为Node的元素从DOM中溢出,该定时器仍会存在,同时,因为回调函数中包含对someResource的引用,定时器外面的someResource也不会被释放。

  1. 子元素存在引起内存泄漏
  2. IE7/8引用计数使用循环引用产生的问题:
function fn(){
  var a={};
  var b={};
  a.pro=b;
  b.pro=a;
}
fn();

fn()执行完毕后,两个对象都已经离开环境,在标记清除方式下是没有问题的,但是引用计数策略下,因为a和b的引用次数不为0,所以不会被垃圾回收器回收内存,如果fn函数被大量引用,就会造成内存泄漏。
怎样避免内存泄漏:
(1) 减少不必要的全局变量,或者生命周期较长的对象,记忆对无用的数据进行垃圾回收;
(2)注意程序逻辑,避免“死循环”之类的;
(3) 避免创建过多的对象,原则:不用了的东西要即使归还。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

简 。单

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值