在很多语言中,开发人员的一项基本任务就是手动跟踪内存的使用情况,这是造成许多问题的根源。而 JavaScript具有垃圾收集机制,执行环境会负责管理代码执行过程中使用的内存
。因此在编写 JavaScript 程序时,开发人员不用在关心内存使用问题。
“原理:找出那些不再继续使用的变量,释放其所占用的内存。垃圾收集器会按固定的时间间隔,周期性的执行这一操作。
JavaScript中最常用的垃圾收集方式是标记清除
,当变量进入环境时,将此变量做标记为进入环境。逻辑上讲,永远不能释放进入环境的变量所占用的内存,因为只要执行流进入相应的环境,就可能会用到它们。而在变量离开环境时,在此标记其为离开环境。
工作流程
给存储在内存中的所有变量加上标记
去掉环境中的变量以及被环境中的变量引用的变量的标记
环境中的变量已经无法再访问到这些变量
了内存清除
工作,销毁那些带标记的值并回收它们所占用的内存空间另一种不常用的垃圾收集策略是引用计数
。
“引用计数的含义是跟踪记录每个值被引用的次数。
工作流程
存在问题
在这样的策略下,出现了比较严重的问题:循环引用
。
“循环引用指的是对象A中包含了一个指向对象B的指针,而对象B中也含有一个指向对象A的指针。
例:
function problem() {
var objA = new Object();
var objB = new Object();
objA.someOtherObject = objB;
objB.anotherObject = objA;
}
在此例子中,objA 和 objB 都通过各自的属性相互引用。也就是说,这两个对象的引用次数都是2。在第一种策略中,我们采用标记清除策略的实现,由于函数执行后,这两个对象都离开了作用域,因此这种相互引用不是个问题。而在我们采用引用计数的策略中,当函数执行完毕后,objA 和 objB 还将存在,因为它们的引用次数永远不会为0。如果程序中含有大量类似的函数甚至被反复调用,将会导致大量的内存得不到回收,从而引发严重的内存问题。
为了解决这样的问题,可以将不再使用它们的时候 手动将变量设置为 null
,意味着切断变量与它此前引用的值的连接:
// 不再使用时
objA = null;
objB = null;
这样,当垃圾收集器下次运行的时候,就会删除这些值并回收它们所占用的内存。
垃圾收集器是周期性运行的,而且如果变量分配的内存数量很可观,那么回收工作量也会随之变大。这种情况下,确定垃圾收集的时间间隔是非常重要的问题。在IE中,JavaScript 引擎的垃圾收集工作方式为:
在有些浏览器中可以主动触发垃圾收集过程,如 window.CollectGarbage() 方法会在IE中起作用。但并不建议手动触发。
在前面介绍过,一般情况下开发人员不必操心内存管理问题。但存在的一个现象是,JavaScript 程序开发面临一个问题。
现象:分配给 Web 浏览器的可用内存通常要比分配给桌面应用的程序要少。
目的:出于安全考虑,防止运行 JavaScript 的网页耗尽全部系统内存而导致系统崩溃。
需求:确保占用最少的内存可以让页面获得更好的性能。
最佳方式:
“
解除引用
——为执行中的代码只保存必要的数据。一旦数据不再有用,最好通过将其值设置为 null 来释放其引用。
例:
function createPerson(name) {
var localPerson = new Object();
localPerson.name = name;
return localPerson;
}
var globalPerson = createPerson('ZhuXingmin');
// 手动解除引用
globalPerson = null;
注:解除一个值的引用,并不意味着自动回收该值所占用的内存,解除引用的真正作用是让值脱离执行环境,以便于垃圾收集器下次运行时将其回收
。
JavaScript 是一门具有自动垃圾收集机制的编程语言,开发人员不必关心内存分配问题。垃圾收集例程如下总结:
往期推荐