JS内存泄漏

217 阅读3分钟

JS避免内存泄漏

为什么要避免

什么是内存泄漏呢?就是有些理应被回收的垃圾,却没被回收,这就造成了垃圾越积越多。

内存泄漏,听起来很遥远,但其实离我们很近很近,我们平时都直接或者间接地去接触过它。例如,有时候你的页面,用着用着就卡了起来,而且随着时间的延长,越来越卡,那这个时候,就要考虑是否是内存泄漏问题了,内存泄漏是影响用户体验的重大问题,所以平时通过正确的代码习惯去避免它,是非常有必要的。

如何监控内存状况

浏览器任务管理器

打开方式:在浏览器顶部右键,打开任务管理器:

打开后,看到内存和JavaScript内存(括号里):

  • 内存:页面里的原始内存,也就是DOM节点的总占用内存
  • JavaScript内存(括号里):是该页面中所有可达对象的总占用内存

那什么是可达对象呢?简单说就是:就是从初始的根对象(window或者global)的指针开始,向下搜索子节点,子节点被搜索到了,说明该子节点的引用对象可达,搜不到,说明该子节点对象不可达。

举个例子:

// 可达,可以通过window.name访问
var name = '东方红东方红'

function fn () {
    // 不可达,访问不了
    var name = '的获得丰厚'
}

Performance

打开方式:F12或者鼠标右键检查打开调试窗口,选择Performance

点击刷新页面 -> 待页面加载好后,点击stop

  • JS Heap:JS堆
  • Documents: 文档
  • Nodes: DOM节点
  • Listeners: 监听器
  • GPU Memory: GPU内存

堆快照

堆快照,就是将当前某一个页面的堆内存拍下照片存起来,同一个页面,执行某个操作前,录制堆快照是一个样,有可能执行完后,录制的堆快照又是另外一个样。

选择Statistics,查看数组,对象,字符串等所占内存

如何避免?

减少全局变量

不要忘记写var,let,const;

未清除定时器

setInterval和setTimeout

合理使用闭包

function fn1() {
    let arr = new Array(100000).fill('Sunshine_Lin')

    return arr
}
let a = []
document.getElementById('btn').onclick = function () {
    a.push(fn1())
}

fn1执行完后,arr会被回收,但是在这段代码中,却是没有被回收,为什么呢?因为fn1执行后,将arr给return出去,然后arr被push进a数组了,而a数组是个全局变量,a数组是不会被回收的,那么a数组里的东西自然也不会被回收,这就导致arr不会被回收,等到点击越来越多次,不可被回收的arr就会越来越多

分离DOM

什么叫分离DOM呢?

<button id="btn">点击</button>

let btn = document.getElementById('btn')
document.body.removeChild(btn)

虽然最后把button给删除了,但是因为全局变量btn对此DOM对象引用着,导致此DOM对象一直没有被回收.

这个问题很好解决,删除button后,顺便把btn设置成null就行了:

btn = null