JS 内存泄漏
2020-04-21 本文已影响0人
行走的蛋白质
什么是内存泄漏?
- 不再用到的内存,没有及时释放,就叫做内存泄漏(memory leak)。
- 大多数语言提供自动内存管理,减轻程序员的负担,这被称为"垃圾回收机制"(garbage collector)。
JavaScript中的内存管理
JavaScript具有自动垃圾回收机制,也就是说,执行环境会负责管理代码执行过程中使用的内存。JS的垃圾收集机制的原理是:找出那些不再继续使用的变量,然后释放其占用的内存。为此,垃圾收集器会按照固定的时间间隔(或代码执行中预订的收集时间),周期性地执行这一操作。
标记清除算法
JS中常用的的垃圾收集方式是标记清除(Mark-and-sweep)。当变量进入环境时,就将这个变量标记为“进入环境”。从逻辑上讲,永远不能释放在环境中的变量所占用的内存。因为只要进入到环境,就会有可能用到它。当变量离开环境时,会将其标记为“离开环境”,在垃圾收集器工作时(一般垃圾收集器在内存不够时工作),会将标记为“离开环境”的变量所占用的内存收回。
引用计数法
引用计数法是垃圾回收的早期策略,在堆中的每个对象都有一个引用来计数,每当有一个地方引用到它时,计数器的值就会加一;引用失效时,计数器值减一,当计数器的值为0时,就认为该对象就是不被使用的,可以进行垃圾回收,但这种算法缺钱,就是很难解决对象之间相互循环引用的问题;
造成内存泄漏的可能
闭包造成内存泄漏的情况
函数内部的函数引用了外层函数的变量并且使用了它的执行环境,这种情况下外层函数被使用的变量和执行环境不会被垃圾回收机制回收
全局变量
- 在JS中不进行声明的变量会成为全局变量,它在应用程序退出之前不会被销毁。若不慎创建了一个无用的全局变量,且该变量存储了大量的数据,则会造成内存泄漏
- 避免:在JavaScript文件最前面添加use strict。在严格模式下不允许使用未声明的变量。
被遗忘的计时器或监听回调
- 若在程序中某个计时器中所需要的引用对象不再存在时,该计时器也就没有作用了,此时必须要将该计时器移除移除,否则会造成内存泄漏。
超出DOM引用
- 有时保存DOM节点内部数据结构很有用。假如你想快速更新表格的几行内容,把每一行DOM存在字典中(JSON键值对)或者数组很意义(每次查找DOM都需要一定的时间消耗)。此时,同样的DOM元素存在两个引用,一个在DOM树中,另一个在字典中。此后如果想要删除这些行时,需要将两处引用都清除,否则会导致内存泄漏
- 还要考虑DOM树内部或子节点的引用问题。如果此时JS代码中保存了表格某一个<td>的引用。将来决定删除整个表格时,直观上以为只会删除除该<td>以外的其他节点。但是事实是:此<td>是表格的子节点,子元素和父元素是引用关系。由于代码保留了<td>的引用,导致整个表格仍待在内存中(简单来说就是会因为一个子节点保留,而导致整个表格都保留,因为子节点会引用父节点,父节点的引用数至少为1))。故保存DOM元素的引用的时候,要小心谨慎。