javascript基础常识问答(七)

什么是内存泄漏,哪些常见操作会造成内存泄漏?

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

1. 介绍

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

怎么区分变量是否没有用,

垃圾收集器通常情况有两种方式跟踪变量

  1. 对于不再有用的变量打上标记,以备将来收回其内存 --> 标记清除(常用)
function test(){
  var a=10;//被标记,进入环境
  var b=20;//被标记,进入环境
}
test();//执行完毕之后a、b又被标记离开环境,被回收
  1. 跟踪记录每个值被引用的次数 --> 引用计数
function test(){
  var a={};//a的引用次数为0
  var b=a;//a的引用次数加1,为1
  var c=a;//a的引用次数加1,为2
  var b={};//a的引用次数减1,为1
}
2. 造成泄露的操作
  1. 意外的全局变量引起的内存泄露

一个未声明变量的引用会在全局对象中创建一个新的变量。在浏览器的环境下,全局对象就是 window,如下:

function fn(val) {
   b = "aaaaa";
}

// 实际上等价于
function fn(val) {
   window.b = "aaaaa";
}

// 类似的
function fn() {
   this.name = "zhangsan";
}
//this 指向全局对象(window)
fn();
  1. 闭包引起的内存泄露

闭包可以维持函数内局部变量,使其得不到释放。
由于是函数内定义函数,并且内部函引用了外部函数声明的变量–这就是闭包。

function fn1(){
   var n=1;
   function fn2(){//在加一个fn2当他的子集
       alert(n);
   }
return fn2(); 
//return出来后 他就给 window了所以一直存在内存中。因为一直在内存中,在IE里容易造成内存>泄漏
}
fn1();

2.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的引用。

//在定义事件处理函数的外部函数中,删除对dom的引用
function bindEvent(){
 var obj=document.createElement("XXX");
 obj.οnclick=function(){
   //Even if it's a empty function
 }
 obj=null;
}
  1. dom对象导致的内存泄漏
//1、给DOM对象添加的属性是一个对象的引用。范例: 
var MyObject = {}; 
document.getElementById('myDiv').myProp = MyObject; 

解决方法:
在window.onunload事件中写上: document.getElementById('myDiv').myProp = null;

//2、DOM对象与JS对象相互引用。范例: 
function Encapsulator(element) { 
this.elementReference = element; 
element.myProp = this; 
} 
new Encapsulator(document.getElementById('myDiv')); 

解决方法:
在onunload事件中写上: document.getElementById('myDiv').myProp = null;

//3、给DOM对象用attachEvent绑定事件。范例: 
function doClick() {} 
element.attachEvent("onclick", doClick); 

解决方法:
在onunload事件中写上: element.detachEvent('onclick', doClick);

  1. 被遗忘的定时器或者回调
var someResouce=getData();
setInterval(function(){
   var node=document.getElementById('Node');
   if(node){       
    node.innerHTML=JSON.stringify(someRe>souce)
   }
},1000)

解决方法:
clearTimeout(***) 当不需要setInterval或者setTimeout时,定时器没有被clear,定时器的回调函数以及内部依赖的变量都不能被回收,造成内存泄漏。如果vue使用了定时器,需要在beforeDestroy 中做对应销毁处理。

  1. 循环引用
//反复重写同一个属性会造成内存大量占用(但关闭IE后内存会被释放)。范例: 
for(i = 0; i < 5000; i++) { 
hostElement.text = "asdfasdfasdf"; 
} 

这种方式相当于定义了5000个属性!
解决方法:
其实没什么解决方法:就是编程的时候尽量避免出现这种情况

  1. 子元素存在引起的内存泄露
// 从外到内执行appendChild。这时即使调用removeChild也无法释放。范例: 
var parentDiv = document.createElement("div"); 
var childDiv = document.createElement("div"); 
document.body.appendChild(parentDiv); 
parentDiv.appendChild(childDiv); 

解决方法:
//从内到外执行appendChild:

var parentDiv = document.createElement("div"); 
var childDiv = document.createElement("div"); 
parentDiv.appendChild(childDiv); 
document.body.appendChild(parentDiv); 
  1. 如果在mounted/created

钩子中使用了on,需要在beforeDestroy中做对应解绑(on,需要在beforeDestroy中做对应解绑(off)处理

beforeDestroy() {
 this.bus.$off('****');
}
  1. 死循环
while(1){
   a++;
}

解决方法:加条件

总结
  1. 减少不必要的全局变量,或者生命周期较长的对象,及时对无用的数据进行垃圾回收;
  2. 注意程序逻辑,避免“死循环”之类的 ;
  3. 避免创建过多的对象 原则:不用了的东西要及时归还。

内存泄露及避免方法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Friday--星期五

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

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

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

打赏作者

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

抵扣说明:

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

余额充值