持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第6天,点击查看活动详情 如果你嫌前面啰嗦,可以直接根据大纲跳转~

前言

前段时间写了 页面内存泄露 到底是啥?谁搞的?问到哪些情况出现能答上来吗,在最后留了一下本文的坑~、

你能学到🍗

检测/排查内存泄漏总结 - 图1

node.js

如果是 node 环境下,
我们可以使用 Node 提供的process.memoryUsage方法。
process.memoryUsage返回一个对象,包含了 Node 进程的内存占用信息。该对象包含五个字段

  • rss (resident set size):所有内存占用,包括指令区和堆栈。
  • heapTotal:”堆”占用的内存,包括用到的和没用到的。
  • heapUsed:用到的堆的部分。
  • external:V8 引擎内部的 C++ 对象占用的内存。
  • arrayBuffers:分配给ArrayBuffers和SharedArrayBuffers的内存,包括所有Node.js的Buffers。

单位是字节

判断内存泄漏主要用heapUsed,而这个方法主要是在Node环境下,所以我们这里不做实操了


除了命令行,我们还可以利用 开发者工具~(本文主要讲这个,实操也只有这个~)

先了解一下 Chrome devtool🔨

很多人应该还没怎么用过开发者工具做这些东西,这里先将一下相关的按钮和图形代表的意思,在后面实操会带着具体操作~

性能 Performance🚀

f12打开开发者工具,选择性能(Performance)
image.png
当你想进行测量时,点击录制,然后进行操作正常的页面点击等操作就行了,配合手动垃圾回收,最后结束录制查看内存情况就好了

内存 Memory🍱

时间轴上的分配插桩

image.png
当你想进行测量时,点击录制,然后进行操作正常的页面点击等操作就行了,就可以看到一些柱子,有蓝色有灰色,蓝色的可能会变成灰色。

  • 蓝色表示当前占用着的内存
  • 变为灰色则表示内存已经被释放

    堆快照

    前面的都只是查看是否有内存泄漏,这个可以抓取两份快照,查看占用内存的对象到底是啥,然后我们可以借助这些信息来抓住可恶的内存小偷。
    具体使用看下面的实操环节~

    demo 准备😛

    先准备一下肯定会出现内存泄漏的场景,就用 不当的 console.log 做例子吧

    index.html

    1. <div id="root">
    2. <button>button</button>
    3. </div>
    4. <script src="./index.js"></script>

    index.js

    1. document.querySelector("button").addEventListener("click", function () {
    2. let big = new Array(999999);
    3. // console.log(big);
    4. });

    实操🪐

    性能

    操作

    我们打开 index.html

  • 打开开发者工具-性能

  • 点击录制
  • 先手动垃圾回收一下清空初始值
  • 接着点击三下 button
  • 接着手动垃圾回收一下试试
  • 最后结束录制

GIF.gif

效果

可以看到我们点击三次 button,JS 堆阶梯上升,并且最后手动内存回收后仍然存在。这正是因为点击事件中创建的数组都被console.log保存了下来导致无法回收
image.png

注释掉的效果

  1. document.querySelector("button").addEventListener("click", function () {
  2. let big = new Array(999999);
  3. //console.log(big); // 把这行代码注释掉
  4. });

你可以将console.log注释掉,之后进行和上面一样的操作,再看看效果
image.png
可以看到每次new Array之后,会先将之前的内存销毁,并且最后手动垃圾回收之后,内存占用与初始值相比基本平稳,也就是说没有内存泄漏了~

内存分配插桩

操作

操作上基本和上面的一样,具体可看动图
GIF.gif

效果

可以看见每次点击按钮都会出现一个蓝色柱子,并且不会变灰。也就是出现了被占用的内存但是不会被回收掉
image.png

注释掉的效果

还是和上面操作一样,将console.log语句注释掉
image.png
可以看见出现蓝色柱子后(除了初始的那一条)很快就会变为灰色,说明之前的内存已经被清除释放~

内存堆快照

我们一开始先什么都不操作录制一份堆快照,然后再点击三次再录制一分堆快照。
现在就得到了堆快照1堆快照2
image.png

比较

然后我们选择与快照1比较对比内存分配,按照大小从大到小排序
image.png
可以看见罪魁祸首是数组

控制

再到控制里看一下,大小从大到小排序
image.png
可以看见确实是console.log的锅~

GC 就是 Garbage Collector),垃圾回收,GC root 就是垃圾回收器的对象

总结

是否有案情(是否有内存泄漏)🤔

  • 内存占用阶梯式上升,有案情
  • 内存占用平稳,无案情

    寻找凶手(哪里有内存泄漏)🤔

    根据内存查看、比对内存堆快照

当然,这里 demo 例子比较简单,所以能比较轻松地查看内存泄漏清空。
实际上,这些工具能看见的内容相对与代码直接报错等排查会少得多,或者说“难看”得多。
这些工具大部分时候都是没法直接给你答案,告诉你谁是元凶。(不然他们为啥不直接warning或者error呢)
他只能提供部分内存信息,可能会告诉你哪些是嫌疑犯,甚至大部分时候这些信息都很难找,因为有时会嵌套地很深
而你需要靠这些信息和自己写代码的经验来排查凶手~

预防

其实排查内存泄漏真的是挺麻烦的~ 所以写代码的时候一定要注意啊,如果你还不太了解出现内存泄漏的场景,可以看看下面的推荐阅读~

推荐阅读