搞懂闭包JavaScript的GC机制
其实不管什么语言,都有一套垃圾回收机制。为什么要有垃圾回收机制?因为内存,程序运行需要内存,如果没有垃圾回收(循环引用,内存泄漏),那么内存占用就会越来越高,轻点说会影响性能卡顿,严重的直接导致崩溃。
JavaScript使用垃圾回收机制来自动管理内存。
JS的回收机制分两种:1.标记清除 2.引用计数。各大浏览器常用的是前者。
比如,Chrome浏览器限制的所能使用的内存极限(64位为1.4GB,32位为1.0GB),这就意味着浏览器将无法直接操作一些大内存对象。
标记清除:
定义和用法:当变量进入环境时,将变量标记"进入环境",当变量离开环境时,标记为:"离开环境"。某一个时刻,垃圾回收器会过滤掉环境中的变量,以及被环境变量引用的变量,剩下的就是被视为准备回收的变量。
到目前为止,IE、Firefox、Opera、Chrome、Safari的js实现使用的都是标记清除的垃圾回收策略或类似的策略,只不过垃圾收集的时间间隔互不相同。
工作流程:
- 垃圾回收器,在运行的时候会给存储在内存中的所有变量都加上标记。
- 去掉环境中的变量以及被环境中的变量引用的变量的标记。
- 再被加上标记的会被视为准备删除的变量。
- 垃圾回收器完成内存清除工作,销毁那些带标记的值并回收他们所占用的内存空间。
引用计数:
定义和用法:引用计数是跟踪记录每个值被引用的次数。
基本原理:就是变量的引用次数,被引用一次则加1,当这个引用计数为0时,被视为准备回收的对象。
简单点来说就是有没有被引用,没有被引用的就会被回收,比如一个方法里面的变量,运行之后这个方法不再被使用就会被回收。
工作流程:
- 声明了一个变量并将一个引用类型的值赋值给这个变量,这个引用类型值的引用次数就是1。
- 同一个值又被赋值给另一个变量,这个引用类型值的引用次数加1。
- 当包含这个引用类型值的变量又被赋值成另一个值了,那么这个引用类型值的引用次数减1。
- 当引用次数变成0时,说明没办法访问这个值了。
- 当垃圾收集器下一次运行时,它就会释放引用次数是0的值所占的内存。
但是循环引用的时候就会释放不掉内存。循环引用就是对象A中包含另一个指向对象B的指针,B中也包含一个指向A的引用。
因为IE中的BOM、DOM的实现使用了COM,而COM对象使用的垃圾收集机制是引用计数策略。所以会存在循环引用的问题。
解决:手工断开js对象和DOM之间的链接。赋值为null。IE9把DOM和BOM转换成真正的JS对象了,所以避免了这个问题。
内存泄露的几种情况:
虽然有垃圾回收机制,但是,我们编写代码操作不当还是会造成内存泄漏。
- 意外的全局变量引起的内存泄漏。
原因:全局变量,不会被回收。
解决:使用严格模式避免。
- 闭包引起的内存泄漏
原因:闭包可以维持函数内局部变量,使其得不到释放。
解决:将事件处理函数定义在外部,解除闭包,或者在定义事件处理函数的外部函数中,删除对dom的引用。
面试题
1)问什么是垃圾
一般来说没有被引用的对象就是垃圾,就是要被清除。 有个例外如果几个对象引用形成一个环,互相引用,但根访问不到它们,这几个对象也是垃圾,也要被清除。
2)如何检垃圾
一种算法是标记 标记-清除 算法。