标记清除
js中最常见的垃圾回收方式是标记清除
标记清除的概念也好理解,从根部出发看是否能达到某个对象,如果能达到则认定这个对象还被需要,如果无法达到,则释放它,这个过程大致分为三步
- 垃圾回收器创建roots列表,roots通常是代码中保留引用的全局变量,在js中,我们一般认定全局对象window作为root,也就是所谓的根部
- 从根部出发,检查所有的roots,所有的childs也会被递归检查,能从root到达的都会被标记为active
- 未被标记为active的数据被认定为不再需要,垃圾回收器开始释放它们
注意:
- 当一个对象零引用时,我们从根部一定无法到达
- 从根部武大到达的不一定是严格意义上的零引用,比如循环引用,所以标记清除要更优于引用计数
引用计数
工作原理:跟踪记录每个值被引用的次数
内存泄漏——无法释放已经不使用的内存
引起内存泄漏的几个原因
1.意外的全局变量引起的内存泄漏(原因:全局变量,不会被回收)
解决:使用严格模式避免
2.闭包引起的内存泄漏(原因:闭包可以维持函数内局部变量,使其得不到释放)
解决:将事件处理函数定义在外部,解除闭包,或者在定义事件处理函数的外部函数中,删除对dom的引用。
3.没有清理的Dom元素引用(原因:虽然别的地方删除了,但是对象中还存在对dom的引用)
解决:手动删除
4.被遗忘的定时器或回调(原因:定时器中的dom的引用,即使dom删除了,但是定时器还在,所以内存中还是有这个Dom)
解决:手动删除定时器和Dom
5.子元素存在引用引起的内存泄漏(原因:div中的ul li得到这个div,会间接引用某个得到的li,那么此时因为div间接引用li,即使li被清空,也还是在内存中,并且只要li不被删除,他的父元素都不会被删除)
解决:手动删除清空