1.什么是垃圾
(1)没有被引用的对象或变量
(2)无法访问到的对象(几个对象引用形成一个环,互相引用)
可达性是指那些以某种方式可以访问到或可以用到的值,它们被保证存储在内存中。
有一组基本的固有可达值,由于显而易见而无法删除:
(1)本地函数的局部变量和参数
(2)嵌套调用链上的其他函数的变量与参数
(3)全局变量
(4)还有一些其他的,内部的
这些值成为根。
如果引用或引用链可以从根访问任何其他值,则认为该值是可访问的。
垃圾回收机制
垃圾回收机制(GC:Garbage Collection):执行环境负责管理代码执行过程中使用的内存。JS的垃圾回收机制是为了以防内存泄漏,内存泄漏的含义就是当已经不需要某块内存时这块内存还存在着,没有被释放,导致该内存无法被使用,垃圾回收机制就是间歇的不定期的寻找到不再使用的变量,并释放掉它们所指向的内存。
垃圾回收的必要性
字符串、对象和数组没有固定的大小,所以只有当它们大小已知时才能对它们进行动态的存储分配。JavaScript程序每次创建字符串、数组或对象时,解释器都要分配内存才存储这个实体。只要像这样动态地分配了内存,最终都要释放这些内存以便它们能够被再次利用;否则,JavaScript的解释器将会消耗完系统中所有可用的内存,造成系统崩溃。
JavaScript有自己的垃圾回收机制(Garbage Collection),JavaScript的解释器可用检测到何时程序不再使用一个对象,当确定了一个对象无用的时候,就说明不再需要这个对象了,就可用把这个对象所占用的内存释放掉。
例如:
var a='use'
var b='over a'
var a=b //将a重写
1
2
3
代码执行以后,‘use’这个字符串就失去了引用(刚开始是被a引用的),系统检测到之后,就会启动垃圾回收机制,释放use字符串的存储空间,以便这些空间可用再被利用。
垃圾回收方式
JavaScript执行环境中的垃圾回收器怎样才能检测到哪块内存可以被回收呢?
通常有两种方式:标记清除(mark and sweep)、引用计数(reference counting)
标记清除
这是JavaScript中最常用的垃圾回收方式。
(1)当变量进入执行环境时(函数中声明变量),就标记这个变量为“进入环境”,当变量离开环境时(函数执行结束),则将其标记为“离开环境”,离开环境之后还有的变量则是需要被删除的变量。
(2)垃圾回收器在运行的时候会给存储在内存中的所有变量都加上标记。
(3)去掉环境中的变量以及被环境中变量引用的变量的标记。
(4)之后再被加上标记的变量即是需要回收的变量(因为环境中的变量已经无法访问到这些变量)
(5)最后,垃圾收集器完成内存清除工作,销毁那些带标记的值,并回收他们所占用的内存空间。
引用计数
这种方式常常会引起内存泄漏,低版本的IE使用这种方式。机制就是跟踪一个值的引用次数,当声明一个变量并将一个引用类型赋值给该变量时该值引用次数加1,当这个变量指向其他一个时该值的引用次数便减一。当该值引用次数为0时,则说明没有办法再访问这个值了,被视为准备回收的对象,每当过一段时间开始垃圾回收的时候,就把被引用数为0的变量回收。引用计数方法可能导致循环引用,类似死锁,导致内存泄露。
bjA和objB相互引用,两个对象的引用次数都是2。函数执行完成之后,objA和objB还将会继续存在,因为他们的引用次数永远不会是0。这样的相互引用如果说很大量的存在就会导致大量的内存泄露。
补充:
常见内存泄漏的原因:
(1)全局变量引起的内存泄露
(2)闭包引起的内存泄露:慎用闭包
(3)dom清空或删除时,事件未清除导致的内存泄漏
(4)循环引用带来的内存泄露