巧用 devtool 检测/排查内存泄漏总结 🤔

2,402 阅读5分钟

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

前言

前段时间写了 一文带你搞懂页面泄露及其常出现场景,在最后留了一下本文的坑~

你能学到🍗

node.js

这里略讲一下,不是重点

如果是 node 环境下,

我们可以使用 Node 提供的process.memoryUsage方法。

process.memoryUsage返回一个对象,包含了 Node 进程的内存占用信息。该对象包含五个字段

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

单位是字节

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


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

先了解一下 Chrome devtool🔨

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

性能 Performance🚀

f12打开开发者工具,选择性能(Performance)

当你想进行测量时,点击录制,然后进行操作正常的页面点击等操作就行了,配合手动垃圾回收,最后结束录制查看内存情况就好了

内存 Memory🍱

时间轴上的分配插桩

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

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

堆快照

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

具体使用看下面的实操环节~

demo 准备🌰

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

index.html

<div id="root">
  <button>button</button>
</div>
<script src="./index.js"></script>

index.js

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

实操🪐

性能🛬

操作

我们打开 index.html

  • 打开开发者工具-性能
  • 点击录制
  • 先手动垃圾回收一下清空初始值
  • 接着点击三下 button
  • 接着手动垃圾回收一下试试
  • 最后结束录制

效果

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

注释掉的效果

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

你可以将console.log注释掉,之后进行和上面一样的操作,再看看效果

可以看到每次new Array之后,会先将之前的内存销毁,并且最后手动垃圾回收之后,内存占用与初始值相比基本平稳,也就是说没有内存泄漏了~

内存分配插桩🍳

操作

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

效果

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

注释掉的效果

还是和上面操作一样,将console.log语句注释掉

可以看见出现蓝色柱子后(除了初始的那一条)很快就会变为灰色,说明之前的内存已经被清除释放~

内存堆快照🌭

我们一开始先什么都不操作录制一份堆快照,然后再点击三次再录制一分堆快照。

现在就得到了堆快照1堆快照2

比较

然后我们选择与快照1比较对比内存分配,按照大小从大到小排序

可以看见罪魁祸首是数组

控制

再到控制里看一下,大小从大到小排序

可以看见确实是console.log的锅~

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

总结⛵

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

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

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

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


当然,这里 demo 例子比较简单,所以能比较轻松地查看内存泄漏清空。

实际上,这些工具能看见的内容相对与代码直接报错等排查会少得多,或者说“难看”得多。

这些工具大部分时候都是没法直接给你答案,告诉你谁是元凶。(不然他们为啥不直接warning或者error呢)

他只能提供部分内存信息,可能会告诉你哪些是嫌疑犯,甚至大部分时候这些信息都很难找,因为有时会嵌套地很深

而你需要靠这些信息和自己写代码的经验来排查凶手~

预防

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

推荐阅读

文中措辞、知识点、格式如有疑问或建议,欢迎评论~你对我很重要~
🌊如果有所帮助,欢迎点赞关注,一起进步⛵这对我很重要~