JavaScript的垃圾回收机制

原理:

Javascript 会找出不再使用的变量,不再使用意味着这个变量生命周期的结束。Javascript 中存在两种变量——全局变量和局部变量,全部变量的声明周期会一直持续,直到页面卸载, 现在各大浏览器通常用采用的垃圾回收有两种方法:标记清除、引入计数(低级浏览器)。

垃圾回收的必要性:

由于字符串、对象和数组没有固定大小,所有当他们的大小已知时,才能对他们进行动态的存储分配。JavaScript程序每次创建字符串、数组或对象时,解释器都必须分配内存来存储那个实体。只要像这样动态地分配了内存,最终都要释放这些内存以便他们能够被再用,否则,JavaScript的解释器将会消耗完系统中所有可用的内存,造成系统崩溃。

垃圾回收的两种实现方式:

1、标记清除
当变量进入环境时,将这个变量标记为“进入环境”;当变量离开环境时,则将其标记为“离开环境”。标记“离开环境”的就回收内存

function f () {
// 函数执行时,a b 分别被标记 进入环境
      var a = 1
      var b= 2     
}
f() // 函数执行结束,a b 被标记 离开环境,被回收

2.引入计数(低级浏览器)
引入计数是一种不太常见的垃圾回收策略是引用计数。当变量声明,第一次赋值时记为1,然后当这个变量值改变时,记录为0,将计数为0的回收

function f() {
    var objA= new Object();
    var objB= new Object();

    objA.n= objB;
    objB.n= objA;
}

/*在这个例子中,objA和objB通过各自的属性相互引用;也就是说这两个对象的引用次数都是2。
在采用引用计数的策略中,由于函数执行之后,这两个对象都离开了作用域,函数执行完成之后,
objA和objB还将会继续存在,因为他们的引用次数永远不会是0。
这样的相互引用如果说很大量的存在就会导致大量的内存泄露。*/

//像上面这种情况就需要手动将变量的内存释放
objA.n = null
objB.n = null

内存泄露

a.意外的全局变量引起的内存泄露
通俗点就是:内存泄漏就是你创建的变量因为一些原因无法被销毁,你自己也访问不到了

原因: 全局变量不会被回收

/*在函数内部声明变量的时候,一定要使用var命令。如果不用的话,你实际上声明的是一个全局变量!(如下代码)
只有当页面被关闭后才会被销毁. 所以这种写法就会造成内存泄露*/
function f1() {
    a= "全局变量"
}
console.log(a);// 全局变量

/*下面这种情况this被指向了全局变量 window, 意外的创建了全局变量. 
如果使用这些全局变量用来暂存大量的数据, 记得在使用后, 对其重新赋值为 null.*/
function f2() {
    this.a= "全局变量"
}
console.log(a);// 全局变量

解决:使用严格模式可以避免

b.闭包引起的

原因: 活动对象被引用,使闭包内的变量不会被释放

/*由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,
否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。*/

function test(){
    var element = document.getElementById('test');//element 用完之后一直驻留在内存中
    var id = element.id;
    element.onclick = function () {
       console.log(id);//这里导致内存泄露
    };
   // element = null;// 元素操作完之后主动销毁
}
test();

解决: 将活动对象赋值为null(element = null;)

c.被清理的DOM元素的引用

原因: 虽然DOM被删掉了,但对象中还存在对DOM的引用

var elements = {
    dom: $("#MathJax_Message")
}
function f() {
    elements.dom.html('MathJax_Message');
}
function removeDom() {
   elements.dom.remove();
}
f();
removeDom();
console.log(elements.dom);
// n.fn.init [div#MathJax_Message, context: document, selector: "#MathJax_Message"]

解决: 将对象赋值为null  // elements.dom=null

d.被遗忘的定时器或回调

原因: 定时器内部实现闭包,回调也是闭包

function fn() {
    return 2
}
var oTxt = fn();
setInterval(function() {
    var oHtml = document.getElementById("test")
    if(oHtml) {
        oHtml.innerHTML = oTxt;
    }
}, 1000); // 每 1 秒调用一次

/*如果后续 oHtml 元素被移除, 整个定时器实际上没有任何作用. 但如果你没有回收定时器,
 整个定时器依然有效, 不但定时器无法被内存回收, 定时器函数中的依赖也无法回收. 在这个案例中的 fn 也无法被回收.*/

解决: 清理定时器clearInterval、null

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值