前端🦠内存泄漏🦠四部曲:了解、检测、定位处理和防治

今天在看一些文章时,偶然看到了一篇有关于内存泄漏的文章,当时就想起了一些自己做过的项目的一些往事。

以前做的客服系统,客服人员在使用的时候,有时会出现页面崩溃的情况,当时我们科室内部派了一些人员去驻场,协助排查问题,其中就有内存泄漏的问题。但是的派驻人员没有我,我也没有专门排查过内存泄漏,只是知道一些有关于内存泄漏的知识和什么会导致内存泄漏,算是知道的比较基础的。今天心血来潮,准备系统地学习和整理输出一篇有关于内存泄漏的文章。

本篇文章是我看过一些相关文章后,按照了解、检测、定位处理和防治的四个步骤来讲述内存泄漏

了解篇

学习内存泄漏相关知识,你肯定要了解它的概念,以及什么会导致内存泄漏。 本章也是按照这两个点进行讲述。

什么是内存泄漏

内存泄漏是指程序中分配的内存空间在不再需要时未被正确释放或回收,导致该内存空间无法被再次使用,最终导致系统内存资源的浪费和程序性能下降的现象

内存泄漏,就是由于没有被浏览器的垃圾回收机制给正常清理内存

在JavaScript中,内存是有生命周期的,主要包括以下几个阶段:

分配内存:当程序中创建变量、对象或其他数据结构时,JavaScript引擎会在内存中分配空间来存储这些数据。

使用内存:在程序执行过程中,变量和对象会被使用和修改,占用内存空间。

释放内存:当某个变量或对象不再被引用或需要时,JavaScript引擎会自动执行垃圾回收机制来释放这部分内存空间,以便再次使用。

垃圾回收:JavaScript引擎会定期或在特定条件下执行垃圾回收,检查内存中不再被引用的对象和变量,并将其释放,以避免内存泄漏和节省系统资源。

在JavaScript中,对象存储在堆内存中,可以通过引用链从根对象访问它们。垃圾收集器是 JavaScript 引擎的一个后台进程,负责识别无法访问的对象、删除它们并回收内存。

以下是垃圾收集器根据对象引用链的示例:

当在内存中应该在垃圾回收周期中清理的对象,却因为另一个对象的无意引用而保持可访问时,就会发生内存泄漏。保留冗余对象在内存中会导致应用程序使用过多的内存,可能导致性能下降。

什么会导致内存泄漏

内存泄漏可能由以下几个常见原因导致:

  • 意外全局变量:全局变量会一直存在于内存中,直到页面关闭或程序结束。如果过多的全局变量没有被及时释放,将会导致内存泄漏
  • 未及时清理定时器和事件监听器:在JavaScript中,如果创建了定时器或事件监听器,但在不再需要它们时未手动清除,这些定时器和监听器会继续占用内存,导致内存泄漏
  • 闭包:闭包是指函数内部定义的函数,它可以访问外部函数的变量。如果闭包中引用了外部函数的变量,并且这些变量不再需要时未被释放,就会导致内存泄漏
  • 缓存:在缓存数据时,如果没有合理地管理缓存的大小和生命周期,可能会导致内存泄漏。过多的缓存数据占用内存空间,而且如果没有及时清理过期的缓存数据,也会导致内存泄漏
  • 循环引用:当两个或多个对象之间相互引用,并且这些对象之间的引用形成了一个闭环时,即使这些对象已经不再被程序所需要,垃圾回收机制也无法释放它们占用的内存空间,从而导致内存泄漏
  • DOM操作:频繁对DOM元素进行创建、删除、修改等操作,但未正确释放这些DOM元素所占用的内存空间,也会导致内存泄漏
  • console导致的内存泄漏 因为打印后的对象需要支持在控制台上查看,所以传递给console.log方法的对象是不能被垃圾回收的。我们需要避免在生产环境用console打印对象。
  • ES6 的一些语法的使用:Map、Set 等

具体示例可参考:www.yuque.com/cuggz/feplu...

检测篇

调试内存问题是一项复杂的任务,我们可以利用 Chrome DevTools 来查看内存图和识别潜在的内存泄漏。 现代浏览器都提供了强大的开发者工具,其中包含了内存分析工具,可以帮助开发人员监控内存使用情况。通过浏览器的内存分析工具,可以查看内存占用情况、对象分配情况、堆快照等信息,从而帮助识别潜在的内存泄漏问题。

在检测时,尽量选择在无痕浏览器中检测,清除浏览器插件和缓存的影响。

使用性能分析器可视化内存消耗

定位内存泄漏的方法:(通过浏览器的性能面板)

  • 打开开发者工具,选择 Performance(性能) 面板,在顶部的 capture 字段勾选 Memory(内存),或直接选择 Memory 面板
  • 点击左上角的录制按钮
  • 在页面上进行各种操作,模拟用户的使用情况,也可以称为"问题复现"
  • 一段时间后,点击对话框的 stop 按钮,面板上会显示这段时间的内存占用情况
  • 如果内存占用基本平稳,则说明不存在内存泄漏;相反,如果内存占用不断增加,则可能存在内存泄漏

选中JS Heap(JS 堆),在下方显示的蓝线代表了这段记录期间JS堆内存信息的变化情况。

有一些大佬表示,根据这条蓝线可以初步判断是否存在内存泄漏:如果这条蓝线持续上升,那很可能存在内存泄漏。 然而,实际上这种说法有些偏颇。JS堆内存占用率的增长并不一定意味着内存泄漏,只能表明有许多未释放的内存存在。要确定这些内存是否真正被使用,或者确实存在内存泄漏,还需要进一步的排查和分析。

Memory(内存):内存快照对比

开发者工具的 Memory (内存)选项,可以更精确地定位内存使用情况。

以下是一些步骤,可以帮助开发人员通过对比内存快照来识别内存泄漏

  • 打开浏览器开发者工具并切换到内存分析工具("Memory")。
  • 在内存分析工具中,可以手动触发一次内存快照,记录当前时刻的内存使用情况。
  • 进行一些操作或者触发一些事件,使得内存中可能存在的内存泄漏问题被激活。
  • 返回到原页面,再次触发内存快照,记录第二次内存使用情况。
  • 对比两次内存快照,查看内存中的对象和数据是否有明显的增加或者未释放的情况。特别要注意查看是否有多余的对象被引用、未释放的事件监听器、定时器等情况。
  • 根据对比结果,定位可能存在内存泄漏的代码段,并进行优化和改进。

通过对比内存快照的方式,开发人员可以更直观地了解内存使用情况,并及时发现潜在的内存泄漏问题,从而提高应用的性能和稳定性。

定位处理篇

从上一章节,我们可以检测出是否存在内存泄漏

本章节主要讲定位内存泄漏,并进行处理。最重要的还是定位,定位到了,处理相对而言就很简单了。 我们可以通过内存快照的对比结果,来定位出导致内存泄漏的文件地址。

切换到Comparison(性能)视图,通过比较多个快照之间的差异来找出内存泄露的对象。

上图对比结果的列表中,需要特别注意这个 #Delta ,如果是正值,就代表新生成的内存多,释放的内存少。其中的闭包项,如果是正值,就说明存在内存泄漏。 我们可以根据#Delta(增量)进行排序,进而确定导致内存泄漏的文件地址。 下面我们到代码里找一个内存泄漏的问题: 这里的内容还是比较多的,我们可以重点关注几个:

  • closure(闭包)

防治篇

内存泄漏是一个常见的问题,特别是在前端开发中。以下是一些常见的方法和技巧,可以帮助开发人员预防和解决内存泄漏问题:

  • ESLint 是一个用于检测 JavaScript 代码中潜在问题的静态代码分析工具,可以帮助开发人员在编码阶段发现潜在的内存泄漏问题。
  • 及时释放不再使用的对象和资源:确保在不需要使用的对象或者资源时及时释放它们,避免长时间占用内存空间。
  • 避免循环引用:当两个对象相互引用时,如果没有正确的释放引用,就会导致内存泄漏。尽量避免循环引用,或者在不需要时手动断开引用。
  • 合理使用事件监听器和定时器:当不再需要使用的事件监听器和定时器时,要确保及时移除它们,以防止内存泄漏
  • 使用合适的数据结构和算法:在编写代码时,选择合适的数据结构和算法是防止内存泄漏的重要因素。避免使用过多的全局变量和嵌套循环等可能导致内存泄漏的操作。
  • 使用浏览器开发者工具进行内存分析:定期使用浏览器开发者工具中的内存分析工具,查看内存使用情况,并及时发现潜在的内存泄漏问题。
  • 使用工具和库进行内存泄漏检测:有一些工具和库可以帮助开发人员检测和定位内存泄漏问题,如Chrome DevTools、Memory Leak Detection等。
  • 进行代码审查和测试:定期进行代码审查和测试,发现潜在的内存泄漏问题,并及时修复。

通过以上方法和技巧,开发人员可以有效预防和解决内存泄漏问题,提高应用的性能和稳定性。

更详细的方案可参考:juejin.cn/post/727201...

参考文献

解决前端内存泄漏:问题概览与实用解决方案

如何在浏览器中定位内存泄漏问题

记录一次前端内存泄漏排查经历

内存泄漏以及eslint内存泄漏排查工具开发

前端内存分析、优化、检测泄露

线上内存泄露监控 内存泄露 js

相关推荐
醉の虾13 分钟前
Vue3 使用v-for 渲染列表数据后更新
前端·javascript·vue.js
张小小大智慧21 分钟前
TypeScript 的发展与基本语法
前端·javascript·typescript
hummhumm31 分钟前
第 22 章 - Go语言 测试与基准测试
java·大数据·开发语言·前端·python·golang·log4j
asleep70143 分钟前
第8章利用CSS制作导航菜单
前端·css
hummhumm1 小时前
第 28 章 - Go语言 Web 开发入门
java·开发语言·前端·python·sql·golang·前端框架
幼儿园的小霸王1 小时前
通过socket设置版本更新提示
前端·vue.js·webpack·typescript·前端框架·anti-design-vue
疯狂的沙粒1 小时前
对 TypeScript 中高级类型的理解?应该在哪些方面可以更好的使用!
前端·javascript·typescript
gqkmiss2 小时前
Chrome 浏览器 131 版本开发者工具(DevTools)更新内容
前端·chrome·浏览器·chrome devtools
Summer不秃2 小时前
Flutter之使用mqtt进行连接和信息传输的使用案例
前端·flutter
旭日猎鹰2 小时前
Flutter踩坑记录(二)-- GestureDetector+Expanded点击无效果
前端·javascript·flutter