在js高程(第3版)上看见的,翻译成大白话就是如下的意思
js具有自动收集垃圾机制。在c++和c语言中,内存是造成许多问题的根源,但是js并不需要担心这个问题,它会找出那些不再使用的变量,释放其占用的内,为此垃圾收集器会按固定的时间间隔周期性的执行这一操作。
局部变量只在执行函数的内部存在,在执行时会在内存栈上分配相应的空间,然后在函数执行完将变量销毁。
垃圾收集器必须跟踪变量判断哪个变量有用,哪个变量没用,通常会采用以下两种方法:
1.标记清除。
最常用的方式是标记清除。在变量进入环境时标记为进入环境,当变量离开环境时标记为离开环境。可以使用任何方式来标记变量,比如翻转特殊位来记录变量何时进入何时离开。
垃圾收集器在运行的时候会给内存里所有变量都加上标记。然后它会去掉环境中的变量以及环境中的变量引用的标记,此后再加上标记的变量会被视为将要删除的变量,因为环境已经用不到这些变量了。最后,垃圾收集器在内存中将这些变量清除并回收它们所占用的内存空间。
2.计数引用。
这个策略是跟踪每个值被引用的次数,第一次声明值时计数为1,当这个值又被赋给另一个变量,则该值的计数+1。而如果引用这个值的变量又引用了别的值,则该值的计数-1,但这种方式有一个致命的漏洞,当出现如下代码时:
function probelom(){
var pro1=new Object();
var pro2=new Object();
pro1.someOtherObject=pro2;
pro2.antherObject=pro1;
}
这种情况下,函数执行完毕,因为彼此互相引用,pro1和pro2的计数都为2,所有函数执行完不会被清除,假如这个函数被多次调用,就会产生大量内存得不到回收,因此,最开始使用这种策略的公司最后放弃了这种策略改用了标记清除。
然而IE中却仍存在着这种烦恼,因为IE的dom对象仍在使用技术引用的策略,在发生下列情况时
var element=document.getElementById("element");
var newobject=new Object();
newobject.element=element;
element.someObject=newobject;
dom对象和js对象之间创建了循环引用,那么dom对象就一直存在于内存中,不会被销毁,除非给手工断开这两个引用值的链接,都赋值为null才会被回收。
newobject.element=null;
element.someObject=null;
IE为了解决这个问题在9以后的版本,dom和bom对象都转换成了真正的js对象,就避免了这两种垃圾收集算法并存导致的问题,也避免了内存泄露。(内存泄露是指在动态分配的堆内存没有回收或者没有得到释放,造成系统内存的浪费,导致运行程序变慢或者系统崩溃等严重后果);
性能问题:
垃圾收集器是周期运行的,而且如果给变量分配的内存数量很多,那么回收工作量也是相当大,在这种情况下,确定垃圾收集的时间间隔是一个很重要的问题。
IE曾因这个问题而声名狼藉,它的收集器是根据内存分配量运行的,具体来讲就是256个变量值,4096个对象或数组(字面量),或者64KB的字符串,达到上述任何一个临界值,都会启动垃圾收集器。这种方式的问题在于,如果一个脚本中包含那么多变量,那么该脚本很可能会在其生命周期中一直保有那么多的变量,这样一来,垃圾收集器不得不频繁运行。由此引发的严重性能问题促使IE7重写了其垃圾收集例程。
新的工作方式为:动态变化临界点。初始临界点与IE6一致,当垃圾收集例程回收的内存分配量低于15%,则各项临界点翻倍,如例程回收了85%的内存分配量,则临界值变回默认值。看似简单的调整,实际极大的提升了IE在运行包含大量js的页面时的性能。
事实上,在有的浏览器中可以出发垃圾收集过程,但我们不建议这样做。在IE中,调用window.CollectGarbage()方法会立即执行垃圾收集。在Opera7及更高版本中,调用window.opera.collect()也会启动垃圾收集例程。