推荐阅读
-
算法实现--V8引擎垃圾回收机制
问题列表
JS垃圾回收有几种方式
什么方式会引起内存泄露
如何避免内存泄漏,有几种方式
JS的栈内存和堆内存??堆内存大小是固定的???
1.垃圾回收方式
JS具有自动垃圾回收机制,GC(Garbage collection会按照固定的时间间隔周期性执行)
GC不是实时的,因为开销比较大,所以会按照固定的时间间隔周期性执行,各个浏览器的时间间隔不一致
标记清除
- 当变量进入环境时,标记为“进入环境”,离开环境时,标记为“离开”
- 垃圾回收器在运行的时候会给存储在内存中的所有变量都加上标记(当然,可以使用任何标记方式)
- 然后,它会去掉环境中的变量以及被环境中的变量引用的变量的标记(闭包)
- 而在此之后再被加上标记的变量将被视为准备删除的变量,原因是环境中的变量已经无法访问到这些变量了
- 最后垃圾回收器完成内存清除工作,销毁那些带标记的值并回收它们所占用的内存空间。
引用计数
IE7、8是用的这种方式,不推荐,IE9把DOM和BOM转换为真正的JS对象了,所以不再使用引用计数
IE中的DOM和BOM的实现使用了C++的COM,而COM的回收机制是引用计数
缺点:循环引用时,造成内存泄露
循环引用:对象A中包含指向对象B的指针,B中包含指向A的引用,当程序执行结束,引用计数不为0,导致无法释放A、B
解决方案:手动设置为null,切断变量与它此前引用的值之间的连接,GC在下次运行时,就会删除这些值,并把它们回收
原理:
跟踪记录每个值被引用的次数,当声明一个变量,并将这个引用类型的值赋值给该变量时,这个引用类型值的引用次数就是1,当引用次数变为0时,就会释放该内存值占用的空间
var a = {}; // a的引用次数是1
-
现代浏览器的回收策略--标记清除,但是垃圾收集的时间间隔互不相同
2.栈内存和堆内存
栈内存保存基本类型的值、和指向引用类型的指针,内存大小是固定的
堆内存保存的是引用类型的值,如数组和对象,内存大小是不固定的
栈内存是先进后出,堆内存是按引用地址读取
操作对象时,实际操作的是对象的引用,而不是实际的对象
堆内存由程序员分配,若程序员不释放,程序结束时会有OS回收,分配方式类似链表
栈内存由OS自动操作释放,使用的是一级缓存,被调用时处于存储空间,调用完毕立刻释放
堆内存放在二级缓存中,生命周期由垃圾回收算法来决定,并不是一旦成为孤儿就会被回收
3.触发垃圾回收的设置?
- IE6--当环境中存在256个变量、4096个对象、64k的字符串任意一种情况的时候就会触发垃圾回收器工作
- 缺点:现代网站都比较复杂,JS中的变量较多,当环境中一直存在这么多变量时,GC会一直在工作,那网站就没办法工作了
- IE7--触发条件动态修改,根据垃圾回收的内存分配量和程序的内存量比较
- GC时,停止响应,会造成页面卡顿,如何优化呢?
- 分代回收方法--变量存储时区分临时、持久区域,多回收临时对象区,少回收持久对象区,减少每次需要遍历的对象,从而减少每次GC耗时
- 增量GC方法--每次处理一点,下次再处理一点,虽然耗时短,但是中断较多,需要上下文频繁切换
4,内存泄露
-
定义:不再用到的内存,没有及时释放,就叫做内存泄漏
-
引起内存泄露的情形
-
垃圾回收不会清除全局变量,全局变量会造成内存泄露,解决方法--使用严格模式
-
未销毁的定时器和回调函数,造成内存泄露
-
定时器的回调函数是个闭包,闭包会造成引用的变量和函数一直保存在内存中,无法释放,造成内存泄露
-
将事件处理函数定义在外部,解除闭包,或者在定义事件处理函数的外部函数中,删除对dom的引用。
-
-
DOM元素的不恰当处理
-
对于DOM元素的引用要及时手动置空
-
虽然别的地方删除了,但对象中还是存在对DOM的引用,比如引用了td元素,但删除了整个表格,实际上td元素仍然保留对其父元素的引用,导致整个表格都无法回收
-
-
5.WeakMap--对于值的引用不计入垃圾回收机制,表示是弱引用
-
只要外部的引用消失,WeakMap 内部的引用,就会自动被垃圾回收清除。
6.如何观测内存泄露
-
Google/Timeline面板,鼠标操作,录制视频,观测折线图,曲折、抖动则有内存泄露
-
Node--process.memoryUsage()
-
* rss(resident set size):所有内存占用,包括指令区和堆栈。
-
* heapTotal:"堆"占用的内存,包括用到的和没用到的。
-
* heapUsed:用到的堆的部分。
-
* external: V8 引擎内部的 C++ 对象占用的内存。
-