利用浏览器DevTools中对React项目进行内存泄露排查

ops/2025/1/13 10:38:57/

利用浏览器DevTools中对React项目进行内存泄露排查

场景:用户在某个页面操作时,在监控平台收集到的数据表现为内存占用有逐步提高的趋势,最先想到的是 DOM 元素卸载后其 JavaScript 对象未能被垃圾回收这类内存泄漏问题。同时,如果在 DOM 元素删除时没有完全清理其对应的 JavaScript 引用,那么内存占用就会只增不减,最终影响用户体验。

步骤一:Performance Monitor定性

Performance Monitor 能够在较小的性能代价下展示出网站应用的若干个影响性能和体验的关键参数随着时间变化(用户操作)的趋势,其关键指标如下所示。

CPU usage 网页使用的CPU百分比。默认显示。
JS heap size JavaScript程序在页面上使用的内存量。默认显示。
DOM Nodes 浏览器中DOM节点的数量(跨选项卡)。默认显示。
JS event listeners 浏览器中JavaScript事件监听器的数量(跨选项卡)。
Documents 浏览器中文档对象的数量(跨选项卡)。
Document Frames 浏览器中文档框架的数量(跨选项卡)。
Layouts / sec 浏览器引擎每秒构建页面布局的次数。
Style recalcs / sec 浏览器引擎每秒计算页面CSS样式的次数。

针对内存泄漏问题,可以重点关注 JavaScript 堆大小和 DOM 节点数的变化趋势,并根据以下原则对内存泄漏进行初步的定性判断

  • 其中任何一个出现只增不减的趋势,则可以定性判断存在内存泄漏问题
  • 如果 JavaScript 堆大小只增不减,而 DOM 节点数趋势平稳,则可以定性只在 JavaScript 上下文中出现了内存泄漏
  • DOM 节点数只增不减往往会伴随着 JavaScript 堆大小的只增不减。此时需要关注二者增加的趋势是否同比(增长速度一致)同频(增长时机一致)
    • 如果同比同频,可以定性只有 DOM 元素卸载未清理引用引发的内存泄漏,JavaScript 堆大小的变化只是伴生现象
    • JavaScript 堆大小增长趋势更加陡峭,可以定性同时存在两个内存泄漏源头

当二者的变化趋势满足同比同频,基本可以确定是对 DOM 元素的引用没有清理导致的内存泄露问题。

步骤二:Detached Elements定位

官方文档:https://learn.microsoft.com/en-us/microsoft-edge/devtools-guide-chromium/memory-problems/dom-leaks

Detached Elements 的功能非常明确,即找到所有没有挂载在 DOM 树上,同时还没有被浏览器引擎垃圾回收的 DOM 元素。因为浏览器的垃圾回收本身就是周期性的行为,所以在进行问题排查前,必须手动触发一次垃圾回收行为,保证剩下的就是要排查分析的目标元素。(记住一个要点:每次录制前需要手动回收,以保证数据准确)

DOM对象是占用内存最高的一类对象之一,因此如果在应用程序中频繁地创建和销毁DOM对象,就容易导致内存泄漏。游离的DOM引用指的是已经不在文档中的DOM节点的引用,但是这些引用仍然被保存在JavaScript的变量、数组和对象中,因此这些DOM节点无法被垃圾回收器回收,从而导致内存泄漏。

步骤三:Memory分析

官方文档:https://learn.microsoft.com/en-us/microsoft-edge/devtools-guide-chromium/memory-problems/

Memory 能够建立当前应用的 JavaScript 堆快照,用于进一步分析页面的 JavaScript 对象以及相互之间的引用关系。在已经定位了泄漏源的基础上,可以借助该工具查明目标 DOM 被什么 JavaScript 对象持有了引用导致无法被垃圾回收。

基于这里的快照,我们可以发现发生泄漏的 DOM 元素的 distance属性 是 7,点击之后可以反向追溯其到 Root(浏览器环境下为 window 对象)的完整路径。当然,持有该 DOM 元素的路径通常不止一条,我们只需要关注最短的那条即可。基于此,我们可以构建出其对象持有路径…

[外链图片转存中…(img-Xi1zHZIP-1719410253318)]

在分析了多个发生泄漏的 DOM 元素之后,我们最终定位到XXXX属性持有了已经被卸载的 DOM 的引用,导致用户只要停留在页面,DOM增删情况越多越多内存泄漏得越多。对相关代码进行处理,及时删除引用即可。

小结

在 React 框架中,为了能够方便地建立 DOM 元素与 FiberNode 之间的关联,由框架生成的 DOM 元素会持有其 FiberNode 对象的引用,FiberNode 中同样持有了相关 DOM 元素的引用。因此,无论是浏览器的 DOM 树还是 React 的 Fiber 树,只要有任意一个节点没有被正确释放引用,其自身以及所有子孙元素在两棵树上的对象都无法被垃圾回收。

因此在React项目中,不仅要关心真实Dom的引用,也要关心虚拟Dom及其Fiber节点的引用情况…


http://www.ppmy.cn/ops/52839.html

相关文章

计组--输入输出系统--复习

文章目录 前言一、概述二、I/O接口三、主机和外设交换信息的方式四、中断系统总结 前言 学无止境,笔勤不辍。今晚加班,再赶一章…有关计组的输入输出系统相关的知识点… 一、概述 外设特点:1.数据传输速度相差较大 2.工作时有独立性,具有自…

【SpringCloud-Seata源码分析2】

文章目录 分支事务注册-客户端分支事务服务端的执行 分支事务注册-客户端 第一篇我们将全局事务启动,以及开启源码分析完成了,现在我们需要看一下分支事务注册。 我们分支事务的开始需要从PreparedStatementProxy#executeUpdate中去看。 public class…

全球无界,语言无阻——魔众帮助中心(多语言)系统全新升级!

🎉亲爱的用户们,你们好!今天,我要向大家隆重介绍一个颠覆传统,助力全球用户的利器——魔众帮助中心(多语言)系统的全新升级版本!🌟 🌐在这个日益全球化的时代,魔众帮助中…

面向对象编程——python

目录 一、面向对象编程 1.1 类和对象 1.2 继承 1.3 封装 1.4 多态 1.5 Python中的面向对象编程 二、类、对象和变量 2.1 类(Class) 2.2.1 类的属性(Class Attributes) 2.2.2 类的方法(Class Methods…

Python列表函数append()和extend()的区别

Python列表提供了两个容易混淆的追加函数:append()和extend()。它们之间的使用区别如下: list.append(obj):对象进栈。将一个对象作为整体追加到列表最后,返回Nonelist.extend(iter):可迭代对象的元素逐个进栈。将一个…

【小学期】操纵数据的DAO设计——以学生管理系统为例

项目结构 student_management │ ├── src │ ├── model │ │ ├── Student.java │ │ └── StudentDAO.java │ │ │ ├── view │ │ └── StudentView.java │ │ │ ├── controller │ │ └── StudentController.java │…

2023年 AI APT可持续攻击的调查研究报告

总览 随着网络技术的不断发展,网络安全威胁也日益严峻。高级持续性威胁(APT)攻击以其目标明确、手段多样、隐蔽性强等特点,成为网络安全领域的重要挑战。本文分析2023年当前 APT 攻击的主要特点、活跃组织、攻击趋势以及漏洞利用…

AI问答-医疗:什么是“手术报台”

手术报台并不是传统意义上的医疗工具或设备,而是一个与手术耗材追溯管理相关的系统或工具。以下是对手术报台的详细解释: 一、定义与功能 手术报台系统,如医迈德手术报台系统,是一款面向医院跟台人员的微信小程序。 它通过手术耗…