javascript篇-----垃圾收集和内存问题
垃圾收集
javascript具有自动垃圾收集机制,也就是说,执行环境会负责管理代码执行过程中使用的内存。这种垃圾收集机制的原理其实很简单:找到那些不再继续使用的变量,然后释放其占用的内存。为此,垃圾收集器会按照固定的时间间隔周期性的执行这一操作。
下面我们来分析一下函数中局部变量的正常生命周期。局部变量只在函数执行的过程中存在。而在这个过程中,会为局部变量在栈内存上分配相应的空间,以便存储它们的值。然后在函数中使用这些变量,直至函数执行结束。此时,局部变量就没有存在的必要了。因此可以释放它们的内存以供将来使用。在这种情况下,很容易判断变量是否还有存在的必要。但并非所有的情况下都这么容易就能得到结论。垃圾收集器必须跟踪哪个变量有用哪个变量没用,对于不再有用的变量打上打上标记,以备将来收回其占用的内存。用于标识无用变量的策略可能因实现而异,但具体到浏览器中的实现,则通常有两种策略:标记清除和引用计数。
标记清除
javascript中最常用的垃圾收集方式就标记清除。当变量进入环境时,就将这个变量标记为“进入环境”。从逻辑上讲,永远不能释放进入环境的变量所占用的内存,因为只要执行流进入相应的环境,就可能会用到它们。而当变量离开环境时,则将其标记为“离开环境”。
垃圾收集器在运行的时候会给存储在内存中的所有变量都加上标记。然后,它会去掉环境中的变量以及被环境中的变量引用的变量的标记。而在此之后再被加上标记的变量将被视为准备删除的变量,原因是环境中的变量已经无法访问到这些变量了。最后,垃圾收集器完成内存清除工作,销毁那些带标记的值并回收它们所占用的内存空间。
引用计数
另一种不太常见的垃圾收集策略叫做引用计数。引用计数的含义是跟踪记录每个值被引用的次数。当声明了一个变量并将一个引用类型值赋给该变量时,则这个值的引用次数就是1。如果同一个值又被赋给另一个变量,则该值的引用次数加1。相反,如果包含对这个值的引用的变量又取得了另外一个值,则这个值的引用次数减1。当这个值的引用次数变为0时,则说明没有办法在访问这个值了,因而就可以将其占用的内存空间回收回来。这样,当垃圾收集器下次在运行时,它就会释放那些引用次数为零的值所占用的内存。
内存问题和管理内存
javascript在进行内存管理以及垃圾收集时面临的问题还是有点与众不同的。其中最主要的一个问题,就是分配给Web浏览器的可用内存数量通常要比分配给桌面应用程序的少。这样做的目的主要是出于安全方面的考虑,目的是防止运行的javaScript的网页耗尽全部全通内存而导致系统崩溃。内存限制问题不仅会影响给变量分配内存,同时还会影响调用栈以及在一个线程中能够同时执行的语句数量。
因此,确保占用最少的内存可以让页面获得最好的性能。而优化内存占用的最佳方式,就是为执行中的代码只保存必要的数据。一般数据不在有用,最好通过将其值设置为null来释放其引用——这个做法叫做解除引用。这个做法适用于大多数全局变量和全局对象的属性。局部变量会在他们离开执行环境的时被解除引用。不过,解除一个值的引用并不意味着自动回收该值所占用的内存。解除引用的真正作用时让值脱离执行环境,以便垃圾收集器下次运行时将其回收。
1 { 2 function createPerson (name) { 3 var localPerson = new Object(); 4 localPerson.name = name; 5 return localPerson; 6 } 7 // 声明全局变量globalPerson 8 var globalPerson = createPerson('lili'); 9 // 手工解除globalPerson引用 10 globalPerson = null; 11 }