我们都知道JavaScript具有自动垃圾收集机制,这也就是说,执行环境会管理代码执行过程中使用的内存。
这种垃圾收集机制的原理很简单:找出那些不再继续使用的变量,然后释放其占用的内存。
垃圾收集器必须跟踪那个变量有用哪个变量没用,对于不再有用的变量打上标记,以备将来收回其占用的内存。用于标识无用的策略可能会因实现而异,但具体到浏览器中的实现,则通常有两个策略。
一.标记清除
1.标记清除是JavaScript中最常用的垃圾收集方式。
2.当变量进入环境时,就将这个变量标记为“进入环境”,当变量离开环境时,则将其标记为“离开环境”。
3.可以使用任何方式来标记变量。
4.垃圾收集器在运行时候会给存储在内存中的所有变量都加上标记。然后,它会去掉环境中的变量以及被环境中引用的变量的标记。而在此之后再被加上标记的变量将被视为准备删除的变量,因为环境中的变量已经无法访问到这些变量了。最后,垃圾收集器完成内存清除工作,销毁那些带标记的值并收回它们所占用的内存空间 。
二.引用计数
另一种不太常用的垃圾收集策略叫做引用计数。
引用计数其实就是跟踪记录每个值被引用的次数。
1.声明一个变量并将引用类型值赋给改变量,这个值的引用次数为1;
2.如果同一个值又被赋给另一个变量,则改引用次数加1;
3.如果包含对这个值引用的变量又取另一个值,该引用次数减1;
4.当这个值得 引用次数为0时,说明无法访问这个值,将其占用的内存空间收回。
5.当垃圾收收集器 下次运行时,释放引用次数为0的值所占用的内存。
下面我们来看一个循环引用的栗子
function problem(){
var objectA = new Object();
var objectB = new Object();
objectA.someOtherObject = objectB;
objectB.anotherObject = objectA;
}
在这个例子 中,objectA和objectB通过各自属性相互引用,也就是说,这两个对象的引用次数都是2。
当采用标记清除策略时,由于函数执行完后,两个对象都离开了作用域,这种相互引用不存在问题。
当采用引用计数策略时,函数执行完毕后,但objectA和objectB依然存在,因为它们的引用次数永远不会为0,假如这个函数被多次调用,就会导致大量内存得不到回收。
所以说,引用计数策略会导致很多麻烦。
性能问题
垃圾收集器是周期性运行的,而且如果分配的内存数量很客观,那么回收工作量也是相当大的。
在这种情况下,确定垃圾收集的时间间隔是一个非常重要的问题。
JavaScript引擎的垃圾收集例程改变了工作方式:触发垃圾收集的变量分配,字面量和数组元素的临界值被调整为动态修正。
管理内存
JavaScript在进行内存管理及垃圾收集时面临一个问题:分配给Web浏览器的可用内存数量通常比分配给桌面应用程序的少。
这样做的目的是:防止运行JavaScript的网页耗尽全部系统内存而导致系统崩溃。
解除引用:为了在执行代码时只保存必要的数据,一旦数据不再有用,最好通过将其值设置为null来释放其引用。
这一做法适用于大多数全局变量和全局对象的属性。
局部变量会在它们离开执行环境时自动被解除引用。
我们来看看下面的栗子:
function createPerson(name){
var localPerson = new Object();
localPerson.name = name;
return localPerson;
}
var globalPerson = createPerson("Jimmy");
//手工解除globalPerson的引用
globalPerson = null;
在这个例子中lacalPerson是一个局部变量,它在createPerson()函数执行完毕后就离开了执行环境,不需要我们去为它解除引用,globalPerson是一个全部变量,我们通过给它设null来手动解除。
解除一个值的引用并不意味着自动收回该值所占用的内存,解除引用的真正作用是让值脱离执行环境,方便垃圾收集器器下次运行时将其收回。
网友评论