javascript具有自动垃圾回收机制,执行环境会负责管理代码执行过程中使用的内存,在编写javascript的过程中也是没有注意内存的问题。今天也好好学习一下。
原理
垃圾收集机制的原理简单说就是:找出那些不再使用的变量,然后释放其占用的内存,垃圾收集器会按照固定的时间,周期性的执行这一操作,
局部变量只是在函数执行的过程中存在。而这个过程,会为局部变量在栈(或堆)内分配相应的空间,以便储存他们的值。然后在函数中使用这些变量,知道函数执行结束。此时局部变量就没有存在的不要了,以此可以释放他们的内存,以供将来使用。在这样的情况下,很是容易判断变量是否有存在的必要,但是,并不是所有的情况都是这样容易的判断就能得出结论。
所以垃圾收集器必须跟踪那个变量有用那个变量无用,对于不再有用的打上标记 ,以便将来回收占用的内存,用于表示无用变量的策略通常有标记清除和引用计数两种。
标记清除
javascript最常用的垃圾收集方式就是标记清除(mark-and-sweep),当变量进入环境(例如:在一个函数中声明一个变量),这个变量标记为’进入环境’,从逻辑上来说的,永远不能释放进入环境的变量所占用的内存,因为只要执行流进入相应的环境。就可能会用到他们。当变量离开时,则将其标记为‘离开环境’,
可以用任何方式来标记变量,比如可以反转某个特殊的位来记录一个变量何时进入环境,或者是使用一个‘进入环境的’变量列表以及一个‘离开环境的’变量列表来记录跟踪那些变量发生了变化。不过说到地,如何记录变量不重要,关键是采取什么策略。
垃圾收集器在运行的时候会给储存在内存中的所有变量加上标记,然后它会去掉环境中的变量以及被环境中的变量引用的变量的标记,而在此后,被加上标记的变量将被视为准备删除的变量,原因是环境中的变量已经无妨访问到他们了,,最后垃圾清除器完成内存的清除工作,销毁那些带有标记的值并回收他们所占的内存空间。
大多数浏览器使用的都是标记清除式的垃圾收集策略。
引用计数
另一种不常见的垃圾收集机制是引用计数。
引用计数的含义是跟踪每个值被引用的次数,当声明一个变量,并将一个引用类性的之赋给它的时候,则这个值的次数就加1,如果同一个值有被付给另一个变量,则该值的引用次数加1,相反,如果包含这个值的变量有去的另一个值,则该值的引用次数减1,当该值的引用次数为0的时候说明没办法再访问这个值了,因此就可以将其占用的内存空间收回来了。这样,当垃圾收集器下次运行时,就会释放那些引用次数为0的值所占的内存。
循环引用
function problem(){
var objectA = new Object();
var objectB = new Object();
objectA.someOtherObject = objectB;
objectB.anotherObject = objectA;
}
对象A中包含一个指向对象B的指针,对象B中也包含一个指向对象A的指针。
在这个例子中,objectA和objectB通过各自的属性相互引用,这两个对象的引用次数都是2。在采用标记清除策略的实现中,由于函数执行之后,这两个对象都离开了作用域,因此这种相互引用不是问题。但在采用引用计数策略的实现中,当函数执行完毕之后,objectA和objectB还将继续存在,因为它们的引用次数永远不会是0。假如这个函数被重复多次调用,就会导致大量内存得不到回收。
性能问题
垃圾收集器是周期性运行的,而且如果为变量分配的内存数量很可观,那么回收工作量也是相当大的。在这种情况下,确定垃圾收集时间间隔是一个非常重要的问题。
这种实现方式的问题在于,如果一个脚本中包含那么多变量,那么该脚本很可能会在其生命周期中一直保有那么多的变量。而这样一来,垃圾收集器就不得不频繁地运行。结果,由此引发的严重性能问题促使IE7重写了其垃圾收集例程。
IE7的javascript引擎的垃圾收集例程改变了工作方式:触发垃圾收集的变量分配、字面量和数组元素的临界值被调整为动态修正。IE7中的各项临界值在初始时与IE6相等。如果垃圾收集例程回收的内存分配量低于15%,则变量、字面量和数组元素的临界值就会加倍。如果例程回收了85%的内存分配量,则将各种临界值重置回默认值。这样,极大地提升了IE在运行包含大量javascript的页面时的性能
事实上,在有的浏览器中可以触发垃圾收集过程。在IE中,调用window.CollectGarbage()方法会立即执行垃圾收集
内存管理
使用具备垃圾收集机制的javascript的主要问题在于:分配给web浏览器的可用内存数量通常要比分配给桌面应用程序的少,目的是防止运行javascript的网页耗尽全部系统内存而导致系统崩溃。内存限制问题不仅会影响给变量分配内存,同时还会影响调用栈以及在一个线程中能够同时执行的语句数量。
因此,确保占用最少的内存可以让页面获得更好的性能。而优化内存占用的最佳方式是:为执行中的代码只保存必要的数据。一旦数据不再有用,最好通过将其值设置为null来释放其引用,这种做法叫解除引用(dereferencing)。这一做法适用于大多数全局变量和全局对象的属性,局部变量会在它们离开执行环境时自动被解除引用.
function createPerson(name){
var localPerson = new Object();
localPerson.name = name;
return localPerson;
}
var globalPerson = createPerson('test');
globalPerson = null;
解除一个值的引用并不意味着自动回收该值所占用的内存。解除引用的真正作用是让值脱离执行环境,以便垃圾收集器下次运行时将其回收。艰难的整理完了,还是有些东西不是很能理解,还有部分的缺失,在以后的实战中在理解啦。