JavaScript具有自动垃圾收集机制,执行环境会负责管理代码执行过程中使用的内存。而代码执行过程中占用内存的为定义的变量,垃圾收集器必须跟踪哪个变量有用哪个变量没用,对于不再有用的变量打上标记。
用于标识无用变量的策略具体到浏览器中的实现,通常有两个策略。
最常用的垃圾收集方式是标记清除(mark-and-sweep),现代浏览器都使用了该方式。当变量进入环境时,就将这个变量标记为“进入环境”。从逻辑上讲,永远不能释放进入环境的变量所占用的内存,因为只要执行流进入相应的环境,就可能会用到它们。而当变量离开环境时,则将其标记为“离开环境”。
垃圾收集器在此利用了作用域链。收集器在运行时会定期给存储在内存中的变量都加上标记,然后从root对象(即全局变量)开始,沿作用域链可以找到脱离执行环境的变量,去掉这些变量和被变量引用的变量的标记,在此之后会被加上“离开环境”标记。最后完成内存清除工作。
引用计数(reference counting)跟踪记录每个值被引用的次数。容易遇到的一个问题为循环引用。 例如:
function problem(){ var objectA = new Object(); var objectB = new Object(); objectA.someOtherObject = objectB; objectB.anotherObject = objectA; }在这个例子中,objectA和objectB通过各自的属性相互引用,故它们的引用次数永远不会为0,导致它们所占内存无法回收。为了避免循环引用问题,最好使用手工释放内存的方式。
JavaScript在进行内存管理及垃圾收集时面临的主要问题是,系统分配给Web浏览器的可用内存通常比分配给桌面应用程序的少。内存限制问题不仅会影响给变量分配内存,同时还会影响调用栈以及在一个线程中能够同时执行的语句数量。
因此,内存占用需要优化,我们可以为执行中的代码只保存必要的数据,即解除引用(dereferencing),通过将数据的值设置为null来释放其引用,适用于大多数全局变量和全局对象的属性。
需要注意,解除引用并不意味着释放内存,这种做法的真正目的是让值脱离执行环境,以便垃圾执行器下次运行时将其回收。