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

3,894 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第29天,点击查看活动详情

核心描述

本文主要针对浏览器中的内存泄漏定位和描述

  • 什么是内存泄漏:在计算机科学中,由于疏忽或错误造成程序未能释放已经不再使用的内存,并非指内存在物理上的消失,而是应用分配某段内存后,由于设计错误,导致在该段内存之前就失去了对该段内存的控制。从而造成了内存的浪费。简单来说就是,不再用到的内存,没有及时释放,就叫做内存泄漏。
  • 定位内存泄漏的方式:
    • 通过浏览器的性能面板
      • 打开开发者工具,选择 Performance 面板,在顶部的 capture 字段勾选 Memory
      • 或直接选择 Memory 面板(在新版本的 Chrome 浏览器中,102.0.5005.61 )
      • 点击左上角的录制按钮
      • 在页面上进行各种操作,模拟用户的使用情况。也可以叫做我们在开发测试时的“问题复现”
      • 一段时间后,点击对话框的 stop 按钮,面板上就会显示这段时间的内存占用情况
      • 如果内存占用基本平稳,则说明不存在内存泄漏,相反,就是存在内存泄漏。
      • 示例如下:

图1.png

  • 常见的内存泄漏场景:
    • 被忽视的全局变量引用
    • 被遗忘的定时器(setInterval)或回调(resize)
    • DOM 引用丢失(就是 dom 被移除了,但是绑定在其身上的各类事件还在)
    • ES6 的一些语法的使用:Map、Set 等
    • console导致的内存泄漏 因为打印后的对象需要支持在控制台上查看,所以传递给console.log方法的对象是不能被垃圾回收的。我们需要避免在生产环境用console打印对象。
    • 第三方库的引用与销毁
      • 比如在 Vue 项目中引入第三方库的示例:避免内存泄漏
      • 比如一些音视频的播放器,在不使用时,要及时的 destory 而非简单的移除其 DOM 元素

知识拓展

  • 闭包与内存泄漏
    • 闭包本身并不会造成内存泄漏,除非代码书写有误
    • 但是对于 IE 来说,在 IE9 之前,对 JScript 对象和 COM 对象使用了不同的垃圾回收机制,所以闭包在这些旧版本 IE 中可能会导致问题。比如在这些版本的 IE 中,把 HTML 元素保存在某个闭包的作用域中,就相当于宣布该元素不能被销毁。
  • 内存管理概述
    • 手动管理内存:
      • 语言:汇编、C/C++、Pascal 等许多编译执行型语言都需要手动管理内存,由程序开发者手动回收无用的数据占用内存
    • 自动管理内存:
      • 语言:Go、Java、C#、VB.net等绝大多数编译、解释执行型语言,还有 JavaScript、Python、PHP 等绝大多数脚本语言都是由运行环境自动管理内存(增加作为对象池的堆的内存、无用对象的垃圾回收等)。
    • 半自动管理内存:
      • 语言:Rust 语言中多数情况下,通过对象的所有权机制可以使得对象的内存申请和释放在编译期就可以确定,这些对象的内存管理可以看成是由编译器自动处理的。对于少数不受所有权机制限制的不安全对象,仍需要手动管理内存。
  • JavaScript 语言的内存管理机制(垃圾回收机制)
    • 引用 - 计数垃圾收集:最初级的垃圾收集算法,IE6、7 的实现方式
    • 标记 - 清除算法:从 2012 年起,所有现代浏览器都使用了标记 - 清除垃圾回收算法。所有对 JavaScript 垃圾回收算法的改进都是基于标记 - 清除算法的改进,并没有改进标记 - 清除算法本身和它对“对象是否不再需要”的简化定义。

参考资料

浏览知识共享许可协议

本作品采用知识共享署名-相同方式共享 4.0 国际许可协议进行许可。