js内存泄露


js内存泄露如何检测?场景有哪些?如何定位到具体代码?

定义

程序中已动态分配的堆内存由于某种原因程序未释放或无法释放引发的各种问题,如浏览器变慢,奔溃,延迟大

引起内存泄漏的操作

  1. 闭包函数使用不当
  2. 未使用的 var 声明的全局变量
  3. 分离的DOM节点
  4. 控制台日志(console.log)
  5. 遗忘定时器

Chrome 控制台查看内存情况

无痕模式

打开Chrome的无痕模式,这样做的目的是为了屏蔽掉Chrome插件对我们之后测试内存占用情况的影响

Performance

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在页面从零到加载完成这个过程中JS Heap(js堆内存)、documents(文档)、Nodes(DOM节点)、Listeners(监听器)、GPU memory(GPU内存)的最低值、最高值以及随时间的走势曲线

Memotry

作用:用于记录页面堆内存的具体情况以及js堆内存随加载时间线动态的分配情况
在这里插入图片描述

1. 先用 Allocation instrumentation on timeline 确认问题

在这里插入图片描述

在开始记录后,我们可以看到图中右上角有起伏的蓝色与灰色的柱形图,其中蓝色表示当前时间线下占用着的内存;灰色表示之前占用的内存空间已被清除释放

2. 再用 Head snapshot 定位代码
3.在 Souces 中 使用 ctrl + p 定位代码文件,确定错误代码具体位置

闭包函数使用不当

// 其中,arr被赋值给 res,arr 被标记为活动变量并一直占用着相应的内存,假如 res 后续用不到,这内存就一直占用 
<button onclick="btnClick()">点击</button>
<script>
    function test() {
        let arr = new Array(1000000);// 一个很大的数组对象
        function fn() {
            let c = [1, 2, 3]
        }
        fn()
        return arr
    }
    let res = []
    function btnClick() {
        res.push(test())
    }
</script>
  1. 先使用 performacne 的曲线图
    在这里插入图片描述
    在这里插入图片描述

在每次录制开始时手动触发一次垃圾回收机制,这是为了确认一个初始的堆内存基准线,便于后面的对比,然后我们点击了几次按钮,即往全局数组变量res中添加了几个比较大的数组对象,最后再触发一次垃圾回收,发现录制结果的JS Heap曲线刚开始成阶梯式上升的,最后的曲线的高度比基准线要高,说明可能是存在内存泄漏的问题

  1. 用 Allocation instrumentation on timeline 手机动态内存分配情况
    在这里插入图片描述

动态内存分配情况图上都会出现一个蓝色的柱形,并且在我们触发垃圾回收后,蓝色柱形都没变成灰色柱形,即之前分配的内存并未被清除,确认内存泄漏的问题是存在的

  1. 用 Head snapshot 定位
    在这里插入图片描述
    在这里插入图片描述

所以选择Object allocated between Snapshot1 and Snapshot2即展示第一条快照和第二条快照存在差异的内存对象分配情况,Array的百分比很高,初步可以判断是该变量存在问题

全局变量

全局变量的内存空间一直不会被释放

分离的DOM节点

<div id="root">
    <div class="child">我是子元素</div>
    <button>移除</button>
</div>
<script>
    let btn = document.querySelector('button')
    let child = document.querySelector('.child')
    let root = document.querySelector('#root')

    btn.addEventListener('click', function () {
        root.removeChild(child)
    })
</script>

在这里插入图片描述

点击按钮后移除.child的节点,虽然点击后,该节点确实从dom被移除了,但全局变量child仍对该节点有引用,所以导致该节点的内存一直无法被释放

在这里插入图片描述

控制台的打印

<button>按钮</button>
<script>
    document.querySelector('button').addEventListener('click', function () {
        let obj = new Array(1000000)

        console.log(obj);
    })
</script>

在这里插入图片描述

先触发一次垃圾回收清除初始的内存,然后点击三次按钮,即执行了三次点击事件,最后再触发一次垃圾回收。查看录制结果发现JS Heap曲线成阶梯上升,并且最终保持的高度比初始基准线高很多,这说明每次执行点击事件创建的很大的数组对象obj都因为console.log被浏览器保存了下来并且无法被回收

避免策略

  1. 减少不必要的全局变量
  2. 避免"死循环"
  3. 避免创建过多的对象
  4. 减少层级过多的引用
  5. 避免定时器遗忘

参考

链接

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

柳晓黑胡椒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值