考核内容: javascript内存泄漏
题发散度: ★★★
试题难度: ★★★
解题思路:
什么是内存泄漏
内存泄露是指当一块内存不再被应用程序使用的时候,由于某种原因,这块内存没有返还给操作系统或者内存池的现象。
再通俗一点的话就是 不再用到的内存,没有及时释放,就叫做内存泄漏(memory leak)。
对于持续运行的服务进程,必须及时释放不再用到的内存。否则,内存占用越来越高,轻则影响系统性能,重则导致进程崩溃。
常见的内存泄漏
以上代码创建了一个作为 element 元素事件处理程序的闭包,而这个闭包则又创建了一个循环引用,匿名函数中保存了一个对 element 对象的引用,因此无法减少 element 的引用数。只要匿名函数在,element 的引用数至少是 1,因此它所占用的内存就永远无法回收。
解决办法:
以上代码可以看出,内存被清理,点击事件会报错;
如何预防内存泄漏
需要了解对象的基本生命周期。当创建一个对象时,JavaScript 会自动为该对象分配适当的内存。从这一刻起,垃圾回收器就会不断对该对象进行评估,以查看它是否仍是有效的对象。
垃圾回收器定期扫描对象,并计算引用了每个对象的其他对象的数量。如果一个对象的引用数量为 0(没有其他对象引用过该对象),或对该对象的惟一引用是循环的,那么该对象的内存即可回收。
常见 JavaScript 内存泄露
1. 意外的全局变量
JavaScript 处理未定义变量的方式比较宽松:未定义的变量会在全局对象创建一个新变量。在浏览器中,全局对象是 window 。
全局变量可能由 this 创建:
在 JavaScript 文件头部加上 'use strict',可以避免此类错误发生。启用严格模式解析 JavaScript ,避免意外的全局变量。
全局变量注意事项
管我们讨论了一些意外的全局变量,但是仍有一些明确的全局变量产生的垃圾。它们被定义为不可回收(除非定义为空或重新分配)。尤其当全局变量用于 临时存储和处理大量信息时,需要多加小心。如果必须使用全局变量存储大量数据时,确保用完以后把它设置为 null 或者重新定义。与全局变量相关的增加内存消耗的一个主因是缓存。缓存数据是为了重用,缓存必须有一个大小上限才有用。高内存消耗导致缓存突破上限,因为缓存内容无法被回收
2 计时器或回调函数
与节点或数据关联的计时器不再需要,对象可以删除,整个回调函数也不需要了。可是,计时器回调函数仍然没被回收(计时器停止才会被回收)。同时,someResource 如果存储了大量的数据,也是无法被回收的。
3. 脱离 DOM 的引用
保存 DOM 节点内部数据结构很有用。假如你想快速更新表格的几行内容,把每一行 DOM 存成字典(JSON 键值对)或者数组很有意义。此时,同样的 DOM 元素存在两个引用:一个在 DOM 树中,另一个在字典中。将来你决定删除这些行时,需要把两个引用都清除。
4:闭包
闭包是 JavaScript 开发的一个关键方面:匿名函数可以访问父级作用域的变量
闭包的作用域一旦创建,它们有同样的父级作用域,作用域是共享的
它引用的变量迫使它保留在内存中(防止被回收)每一个闭包作用域携带一个指向大数组的间接的引用,造成严重的内存泄露。
答案:错误的是
B. 如果一个对象的引用数量为 0,或对该对象的惟一引用是循环的,那么该对象的内存不可回收。