ECMAScript垃圾收集

JavaScript具有强大的垃圾回收功能,执行环境负责管理代码执行过程中使用的内存。其基本原理是:在执行环境中找出那些不再继续使用的变量,然后释放其占用的内存。垃圾收集器会按照系统编写号的时间间隔,周期性地执行操作。

局部变量的生命周期

一个函数中局部变量正常生命周期,局部变量只在函数执行的过程中存在,而在执行的过程中,会为,局部变量在栈或者堆内存上分配内存空间,以便存储他们的值。然后再函数中使用这些变量,直至函数执行结束。在这个时候,局部变量就没有存在的必要了,因此可以释放它们的内存供将来变量使用。

function car() {
    var wheel = 100;
    return console.log(wheel);//
}
car();
console.log(wheel);//不能够访问,输出错误

垃圾收集器想要收集废掉的变量,可以在其废掉的变量打上标记,用于收回占用的内存,标识废掉的变量策咯会因实现而不同,在浏览器中实现,通常有两种策咯。

标记清除

这个JavaScript中最常用的垃圾收集方式,每当一个变量进入环境,就将这个变量标记为“进入环境“。从逻辑上讲,永远不能释放进入环境的变量所占用的内存,因为只要执行流进入相应的环境,就会使用到,而当变量离开环境时,则标记为”离开环境“。

ECMAScript垃圾收集

引用计数

引用计数一般的原理是:声明一个变量,则该值的引用次数加1,如果同一个值又被赋给另一个变量,则该值的引用吃书加1,相反,如果包含对这个值引用的变量又取得了另外一个值,那么这个值引用次数减1,当这个值的引用次数变成0时,则说明没有办法再访问这个值了,因而就可以将其占用的内存空间收回来。

问题:循环引用

循环引用指的是,A对象中包含一个指向B对象的指针,而对象B中也包含一个指向对象A的引用。

function problem() {
    var objectA = new Object();
    var objectB = new Object();
    
    objectA.prototype1 = objectB;
    objectB.prototype2 = objectA;
}

上述代码中,每当执行完毕后,构造的两个对象还会继续存在,因为它们的引用计数策咯实现不会是0。重复调用会产生大量的内存无法收集。

下面简单的例子,展示了使用COM对象导致的循环引用问题:

var element = document.getElementById("some_element");
var myObject = new Object();
myObject.element = element;
element.someObject = myObject;

这个例子,DOM元素element与一个原生JavaScript对象myObject之间创建了引用。myObject的element属性指向element对象;而变量element也有一个属性叫someObject指向myObject,由于存在这个循环引用,即使例子中的DOM从页面中移除,它也永远不会被回收。

怎么解决这个问题呢?

在不使用它们的时候手工断开原生JavaScript对象与DOM之间的连接:

myObject.element = null;
element.someObject = null;

将变量设置null,可以切断与它之前的连接,在下次运行时就会删除这些值并回收它们占用的内存。

事实上JavaScript是一门具有自动垃圾回收机制的编程语言,我们不必关心内存分配问题。

总结:

  1. 离开作用域的值将被自动标记为可回收,因此将在垃圾收集期间被删除。
  2. 标记清除是目前主流的垃圾收集算法,这种算法的思想是给当前不使用的值加上标记,然后回收。
  3. 引用计数,思想是跟踪记录所有值被引用的次数。
  4. 解除变量的引用不仅有助于消除循环引用现象,而且对垃圾收集也有好处。

如果有错误或者不严谨的地方,请务必给予指正,十分感谢。如果您喜欢或者有所启发,欢迎添加收藏,一起加油学习啊。

相关推荐