Meta开源JavaScript内存泄漏监测工具MemLab
一、MemLab简介
上周,Facebook母公司Meta 宣布了开源 MemLab,一个基于 Chromium 的浏览器的 JavaScript 应用程序内存泄漏监测工具。同时,Facebook 技术团队指出:“应用程序的性能和功能正确性问题通常会被用户立即留意到。然而内存泄漏却不一样,它不容易被立即察觉,但它每次都会吃掉一大块内存,使得整个网络会话的响应变得非常慢。”
为了帮助开发人员解决这个问题,Meta 构建了MemLab,它可以自动进行内存泄漏检测并更容易找到泄漏的根本原因。据官方公告称,Meta 内部使用它成功地控制了不可持续的内存增长,并识别了产品和基础设施中的内存泄漏和内存优化机会。目前,Meta 已经在 GitHub 上开源了 MemLab。
Facebook在 2020 年被重新设计为单页应用程序 (SPA),该应用程序的大部分渲染和导航使用客户端 JavaScript。而 Meta 的大多数其他流行网络应用程序都使用了类似的架构来构建,包括 Instagram 和 Workplace。
虽然这种架构使其能够提供更快的用户交互、更好的开发人员体验和更像应用程序的感觉,但在客户端维护 Web 应用程序状态会使有效管理客户端内存变得更加复杂。且内存泄漏的后果在单页应用程序(SPA)中更为严重,因为用户可能会在较长时间内持续与页面交互,而 MemLab 就是专为这种场景设计的。
在许多情况下,JavaScript 可能会泄漏内存。比如,Facebook 工程师 Liang Gong 和 Glenn Conner 就在公告中谈到,当你向 Chrome 控制台发送一个对象时,Chrome 会对其进行隐藏引用,以防止它被收集。另外,auth0 工程师 Sebastian Peyrott 也曾谈到,其他可能出现泄漏或未绑定内存增长的情况则与意外使用全局变量、忘记计时器或回调以及 DOM 外引用有关。
虽然 Chrome 开发者工具提供了检查 JavaScript 代码的内存行为的基本手段,比如时间线视图和配置文件视图,但这并不直接,也不能自动化。相反,MemLab 则可以很容易地集成到 CI/CD 管道中,Gong 和 Conner 介绍道。
二、工作原理
MemLab 的工作原理是通过预定义的测试场景运行 headless 浏览器并对 JavaScript heap snapshots 进行差异分析来发现内存泄漏。要达到这一目的,需要经过如下几步:
- 导航到页面并返回;
- 查找未释放的对象;
- 显示泄露追踪结果。
据悉,MemLab 使用了一个名为“Puppeteer”的 Node.js 库。它可以控制 Google Chrome 或其它基于 Chromium 内核打造的浏览器,且默认情况下以 headless 模式运行(方便命令行交互)。
Facebook 工程师解释称,MemLab 的工作方式就是导航到一个页面、然后离开。正常情况下,可预计该页面分配的大部分内存也将被释放。但若没有被释放,则意味其存在极高的内存泄露可能性。
对于浏览器内存泄漏检测,MemLab 需要开发人员提供的唯一输入是一个测试场景文件,该文件定义了如何通过 overriding Puppeteer API 和 CSS 选择器的三个回调来与网页进行交互。MemLab 会自动对 JavaScript heap 进行差异化处理,完善内存泄漏,并对结果进行汇总。
MemLab 的另一特性,就是提供了 JavaScript 堆的图形视图、启用了用于检查堆快照的 API 。这意味着开发者能够编写开展内存断言的测试,例如声明某个对象将不再存在于内存中。
此外还有一个用于查找重复字符串实例的工具,在某个案例中,团队发现字符串占用了 70% 的堆、且其中半数至少有一个重复的实例。包括 Chrome、Edge、Firefox 在内的浏览器,都有附带内存检查工具。但正如以为开发者在 Hacker News 上吐槽的那样,这些开发工具难以在调试过程中揪出内存泄露的问题。
除了内存泄漏检测之外,MemLab还包括一组用于查找内存优化机会的内置CLI命令和api,并提供如下的功能:
- 堆内容分解
- 监测单个对象的内存使用情况
- 查找重复的字符串实例
比如,监测浏览内存泄漏部分UI。
跟踪UI内存泄漏的整个链路。
三、基本使用
3.1 安装与使用
首先,需要全局安装MemLab插件,安装的命令如下:
npm install -g memlab
例如下面是找到谷歌Maps中的内存泄漏的例子,我妈可以创建一个场景文件来定义如何与谷歌Maps进行交互,比如将其命名为test-google-maps.js。
function url() {return 'https://www.google.com/maps/@37.386427,-122.0428214,11z';
}async function action(page) {await page.click('button[aria-label="Hotels"]');
}async function back(page) {await page.click('[aria-label="Clear search"]');
}module.exports = {action, back, url};
现在使用下面的命令运行上面的js代码, 当memlab与web页面进行交互时就会运行内置的泄漏检测器检测内存泄漏。
memlab run --scenario test-google-maps.js
执行结束之后,Memlab就会打印内存泄漏结果,显示每个泄漏对象集群的一个代表性保留跟踪。
MemLab found 46 leak(s)
--Similar leaks in this run: 4--
--Retained size of leaked objects: 8.3MB--
[Window] (native) @35847 [8.3MB]--20 (element)--->[InternalNode] (native) @130981728 [8.3MB]--8 (element)--->[InternalNode] (native) @130980288 [8.3MB]--1 (element)--->[EventListener] (native) @131009888 [8.3MB]--1 (element)--->[V8EventListener] (native) @224808192 [8.3MB]--1 (element)--->[eventHandler] (closure) @168079 [8.3MB]--context (internal)--->[<function scope>] (object) @181905 [8.3MB]--bigArray (variable)--->[Array] (object) @182925 [8.3MB]--elements (internal)--->[(object elements)] (array) @182929 [8.3MB]
...
接着,我们就可以通过这些捕获的跟踪信息定位到里面的方法。
当然,我没也可以使用Memlab查看基于从Chromium、Hermes、memlab或任何node.js或electronic .js程序中获取的单个JavaScript堆快照检测到的内存问题。
memlab view-heap --snapshot <PATH TO .heapsnapshot FILE>
然后,我没可以使用对象的id,比如node-id @28173来精确定位特定的堆对象。
当然,Memlab也支持自定义的检漏器,自定义检漏器时需要在场景文件中添加一个filterLeak文档。对于目标交互分配的每个未释放的堆对象(节点)将调用filterLeak。
function filterLeak(node, heap) {// ... your leak detector logic// return true to mark the node as a memory leak
};
heap是最终JavaScript堆快照的图形表示。
3.2 堆分析与研究
除了检测内存泄露意外,Memlab还提供了很多其他有用的命令,比如查看某个对象在运行的交互过程中的整个链路。
memlab analyze unbound-object
获取V8/hermes .heapsnapshot文件。
memlab analyze unbound-object --snapshot-dir <DIR_OF_SNAPSHOT_FILES>
使用memlab analyze查看所有内置内存分析。
memlab trace --node-id <HEAP_OBJECT_ID>
3.3 Memlab API
Memlab的npm包支持在浏览器中启动端到端运行并检测内存泄漏。
const memlab = require('memlab');const scenario = {url: () => 'https://www.google.com/maps/@37.386427,-122.0428214,11z',action: async (page) => await page.click('button[aria-label="Hotels"]'),back: async (page) => await page.click('[aria-label="Clear search"]'),
}
memlab.run({scenario});
3.4 内存断言
Memlab支持在Node.js程序中进行Jest测试,也可以使用图视图API来获得其自身状态的堆图视图,执行自内存检查,并编写各种内存断言。
import type {IHeapSnapshot} from '@memlab/core';
import {config, takeNodeMinimalHeap, tagObject} from '@memlab/core';
test('memory test', async () => {config.muteConsole = true;const o1 = {};let o2 = {};tagObject(o1, 'memlab-mark-1');tagObject(o2, 'memlab-mark-2');o2 = null;const heap: IHeapSnapshot = await takeNodeMinimalHeap(); //断言函数expect(heap.hasObjectWithTag('memlab-mark-1')).toBe(true);//断言函数expect(heap.hasObjectWithTag('memlab-mark-2')).toBe(false);
}, 30000);
附件:github.com/facebookinc…
最后
最近还整理一份JavaScript与ES的笔记,一共25个重要的知识点,对每个知识点都进行了讲解和分析。能帮你快速掌握JavaScript与ES的相关知识,提升工作效率。
有需要的小伙伴,可以点击下方卡片领取,无偿分享
Meta开源JavaScript内存泄漏监测工具MemLab相关推荐
- 介绍两个非常好用的Javascript内存泄漏检测工具
内存泄漏对开发者来说一般很难检测因为它们是由一些大量代码中的意外的错误引起的,但它在系统内存不足前并不影响程序的功能.这就是为什么会有人在很长时间的测试期中收集应用程序性能指标来测试性能. 最简单的检 ...
- Android开源框架——内存泄漏检测工具 LeakCanary
开源地址:https://github.com/square/leakcanary FAQ : https://github.com/square/leakcanary/wiki/FAQ 配置 bui ...
- MLeaksFinder :腾讯开源的 iOS 内存泄漏检测工具
一.工具简介 MLeaksFinder :腾讯开源的 iOS 内存泄漏检测工具 工具优势:在日常开发调试或测试业务逻辑过程中,可以自动发现并警告内存泄漏.暂时没有发现误报:基本上报了leak的 进去 ...
- 内存泄漏检测工具(转载)
内存泄漏检测工具2007年08月08日 1. ccmalloc-Linux和Solaris下对C和C++程序的简单的使用内存泄漏和malloc调试库. 2. Dmalloc-Debug ...
- iOS之深入定制基于PLeakSniffer和MLeaksFinder的内存泄漏检测工具
一.背景 在编写日常业务代码时,或多或少都会引入一些导致内存泄漏的代码,而这种行为又很难被监控,这就导致应用内存泄漏的口子越开越大,直接影响到线上应用的稳定性. 虽然 Xcode 的 Instrucm ...
- Android内存泄漏检测工具使用手册
Android内存泄漏检测工具使用手册 前言 LeakCanary 在Android中接入LeakCanary LeakCanary内存泄漏分析 内存泄漏上报到服务端 Shark Shark分析当前应 ...
- VLD内存泄漏检测工具
VLD,检测程序中内存泄漏的工具,检索的相关资料都是说在debug模式下才可以用,针对发布前的版本内存泄漏问题还是想直接做release版本检测更实用.在开源代码的提交记录中找到了相关表述,如下图: ...
- Linux 下几款程序内存泄漏检查工具
Linux 下几款程序内存泄漏检查工具 chenyoubing | 发布于 2016-07-23 10:08:09 | 阅读量 93 | 无 写这篇博客的原因呢是因为自己在编写基于Nginx磁盘缓存管 ...
- 插桩valgrind_基于动态插桩的CC++内存泄漏检测工具的设计与实现.pdf
基于动态插桩的CC++内存泄漏检测工具的设计与实现.pdf 第32卷第6期 计 算 机 应 用 研 究 V01.32No.6 20l5年 6月 ApplicationResearchofCompute ...
最新文章
- CodeVs 1059 汽车装油
- 【codevs2131】【BZOJ1924】所驼门王的宝藏,tarjan+拓扑DP
- SpringBoot yml 配置
- 怎样知道别人在蹭我家wifi?
- python提高——类(私有化,封装、继承、多态)
- JAVA8的双重循环怎么优化_Java8处理List的双层循环问题
- 被逼至“盗版合法化”,俄罗斯要把 RuTracker 放出来了?
- Hadoop学习路径
- headfirstjava_1.BreakingTheSurface
- Linux下文件实时自动同步备份
- phpMyAdmin下载
- 2021福州金桥学校高考成绩查询,2021年福建高考成绩排名及成绩公布时间什么时候出来...
- AFM测试图像假象及其应对
- 直播APP搭建常见难点的解决方案
- zookeeper 分布式barrier
- html阅读器 怎样卸载,怎样彻底卸载掉金山pdf阅读器?
- 农村居民和谐消费模式构建及实现途径
- ExternalInterface的call函数返回null的原因分析(AS2)
- qq空间微博等更多社交平台分享
- 人脸识别的时候,一定要穿上衣服,否则 ...