Memlab,一款分析 JavaScript 堆并查找浏览器和 Node.js 中内存泄漏的开源框架

Memlab 是一款 E2E 测试和分析框架,用于发现 JavaScript 内存泄漏和优化机会。
Memlab 是 JavaScript 的内存测试框架。它支持定义一个测试场景(使用 Puppeteer API),教 Memlab 如何与您的单页应用程序(SPA)交互,Memlab 可以自动处理其余的内存泄漏检查:
- 与浏览器交互并获取
JavaScript堆快照 - 分析堆快照并过滤掉内存泄漏
- 聚合和分组类似的内存泄漏
- 生成用于内存调试的保留器跟踪
安装 Memlab
npm install -g memlab
memlab help
在 Demo App 中检测泄漏
使用 Memlab 检测分离的 DOM 元素的教程。Demo 源码:
设置示例 Web App
当您单击 “Create detached DOMs” 按钮时,Demo app 会泄漏分离的 DOM 元素。每次单击都会创建 1024 个分离的 DOM 元素,这些元素由 window 对象引用。

// @nolint
import Link from 'next/link';
import React from 'react';
export default function DetachedDom() {
const addNewItem = () => {
if (!window.leakedObjects) {
window.leakedObjects = [];
}
for (let i = 0; i < 1024; i++) {
window.leakedObjects.push(document.createElement('div'));
}
console.log('Detached DOMs are created. Please check Memory tab in devtools')
};
return (
<div className="container">
<div className="row">
<Link href="/">Go back</Link>
</div>
<br />
<div className="row">
<button type="button" className="btn" onClick={addNewItem}>
Create detached DOMs
</button>
</div>
</div>
);
}
源文件:packages/e2e/static/example/pages/examples/detached-dom.jsx
1. 克隆仓库
要在本地机器上运行 demo,请克隆 memlab github 存储库:
git clone git@github.com:facebookincubator/memlab.git
2. 运行示例 App
从 Memlab 项目的根目录运行以下命令:
cd packages/e2e/static/example
npm install
npm run dev
这将启动一个示例 Nextjs app。让我们通过从浏览器访问 http://localhost:3000 来确保它正在运行:

这里测试的是 Example 1。
查找内存泄漏
1.创建一个场景文件
// @nolint
// memlab/packages/e2e/static/example/scenario/detached-dom.js
/**
* 我们要运行的场景的初始 `url`。
*/
function url() {
return "http://localhost:3000/examples/detached-dom";
}
/**
* 指定 memlab 应如何执行您要测试该 action 是否导致内存泄漏的 action。
*
* @param page - Puppeteer's page object:
* https://pptr.dev/api/puppeteer.page/
*/
async function action(page) {
const elements = await page.$x(
"//button[contains(., 'Create detached DOMs')]"
);
const [button] = elements;
if (button) {
await button.click();
}
// 从 memlab 清理外部引用
await Promise.all(elements.map(e => e.dispose()));
}
/**
* 指定 memlab 应如何执行将重置您在上面执行的 action 的 action。
*
* @param page - Puppeteer's page object:
* https://pptr.dev/api/puppeteer.page/
*/
async function back(page) {
await page.click('a[href="/"]');
}
module.exports = { action, back, url };
这个文件在 packages/e2e/static/example/scenario/detached-dom.js。
2.运行 memlab
这可能需要几分钟:
cd packages/e2e/static/example
npm run dev # 注意启动 Demo
memlab run --scenario scenarios/detached-dom.js

3.调试泄漏跟踪
对于每个泄漏的对象组,memLab 打印一个具有代表性的泄漏跟踪。

让我们从上到下分解结果:
第 1 部分:浏览器交互面包屑显示了按照我们的场景文件中指定的方式执行的浏览器交互(导航)memlab。
page-load[6.5MB](baseline)[s1]- 初始页面加载时 JavaScript 堆大小为6.5MB。baseline堆快照将在磁盘上保存为s1.heapsnapshot。action-on-page[6.6MB](baseline)[s2]- 单击“Create detached DOMs”按钮后,堆大小增加到6.6MB。revert[7MB](final)[s3]- 在离开触发内存泄漏的页面后,该网页最终达到了 7MB。
第 2 部分:泄漏跟踪的总体摘要
1024 leaks- 有 1024 个泄漏的对象。example app的第 12 行在 for 循环中创建了 1024 个分离的 DOM 对象。Retained size- 泄漏对象集群的聚合保留大小为 143.3KB(内存泄漏根据保留跟踪的相似性分组在一起)。
第 3 部分:每个泄漏簇的详细代表泄漏跟踪
泄漏跟踪是从 GC 根(垃圾收集器遍历堆的堆图中的入口对象)到泄漏对象的对象引用链。跟踪显示泄漏的对象为何以及如何在内存中仍然保持活动状态。 打破引用链意味着泄漏的对象将不再可以从 GC 根访问,因此可以进行垃圾回收。
通过从原生 Window(即 GC 根)向下逐个跟踪泄漏跟踪,您将能够找到应该设置为 null 的引用(但这不是由于bug 引起的)。
map- 这是正在访问的对象的V8 HiddenClass(V8 在内部使用它来存储有关对象形状的元信息和对其原型的引用 - 在此处查看更多信息)- 在大多数情况下,这是 V8 实现细节,可以忽略。prototype- 这是Window类的实例。leakedObjects- 这表明leakedObjects是Window对象的一个属性,大小为148.5KB,指向一个Array对象。0- 这表明分离的HTMLDIVElement(即当前未连接到DOM树的DOM元素)被存储为leakedObjects数组的第一个元素(由于显示所有1024条泄漏痕迹是压倒性的,Memlab只打印一个具有代表性的泄漏痕迹。即属性0而不是属性0->1023)
简而言之,从 Window 对象到泄漏对象的泄漏跟踪路径为:
[window](object) -> leakedObjects(property) -> [Array](object)
-> 0(element) -> [Detached HTMLDIVElement](native)
与示例中的泄漏代码匹配:
window.leakedObjects = [];
for (let i = 0; i < 1024; i++) {
window.leakedObjects.push(document.createElement('div'));
}
更多
- 官网及 Demo
- 文档
- Meta Engineering 博客文章
Memlab,一款分析 JavaScript 堆并查找浏览器和 Node.js 中内存泄漏的开源框架的更多相关文章
- JavaScript、jQuery、HTML5、Node.js实例大全-读书笔记1
技术很多,例子很多,只好慢慢学,慢慢实践!!现在学的这本书是[JavaScript实战----JavaScript.jQuery.HTML5.Node.js实例大全] 第 3 章 用 JavaScri ...
- Chrome 浏览器垃圾回收机制与内存泄漏分析
Chorme 浏览器中的垃圾回收和内存泄漏 垃圾回收 通常情况下,垃圾数据回收分为手动回收和自动回收两种策略. 手动回收策略,何时分配内存.何时销毁内存都是由代码控制的. 自动回收策略,产生的垃圾数据 ...
- js的内存泄漏场景、监控以及分析
内存泄漏 Q:什么是内存泄漏? 字面上的意思,申请的内存没有及时回收掉,被泄漏了 Q:为什么会发生内存泄漏? 虽然前端有垃圾回收机制,但当某块无用的内存,却无法被垃圾回收机制认为是垃圾时,也就发生内存 ...
- JavaScript、jQuery、HTML5、Node.js实例大全-读书笔记3
技术很多,例子很多,只好慢慢学,慢慢实践!!现在学的这本书是[JavaScript实战----JavaScript.jQuery.HTML5.Node.js实例大全] JavaScript.jQuer ...
- JavaScript、jQuery、HTML5、Node.js实例大全-读书笔记2
技术很多,例子很多,只好慢慢学,慢慢实践!!现在学的这本书是[JavaScript实战----JavaScript.jQuery.HTML5.Node.js实例大全] JavaScript.jQuer ...
- Node.js中针对中文的查找和替换无效的解决方法
Node.js中针对中文的查找和替换无效的解决方法. //tags的值: tag,测试,帖子 var pos1 = tags.indexOf("测"); //这里返回-1 ta ...
- 编写浏览器和Node.js通用的JavaScript模块
长期以来JavaScript语言本身不提供模块化的支持, ES6中终于给出了 from, import等关键字来进行模块化的代码组织. 但CommonJS.AMD等规范已经被广为使用,如果希望你的Ja ...
- JavaScript -- 时光流逝(六):js中的正则表达式 -- RegExp 对象
JavaScript -- 知识点回顾篇(六):js中的正则表达式 -- RegExp 对象 1. js正则表达式匹配字符之含义 查找以八进制数 规定的字符. 查找以十六进制数 规定 ...
- JavaScript -- 时光流逝(八):js中的事件Event的使用
JavaScript -- 知识点回顾篇(八):js中的事件Event的使用 事件通常与函数配合使用,这样就可以通过发生的事件来驱动函数执行. (1) onabort : onabort 事件会在图像 ...
随机推荐
- 本地使用 Docker Compose 与 Nestjs 快速构建基于 Dapr 的 Redis 发布/订阅分布式应用
Dapr(分布式应用程序运行时)介绍 Dapr 是一个可移植的.事件驱动的运行时,它使任何开发人员能够轻松构建出弹性的.无状态和有状态的应用程序,并可运行在云平台或边缘计算中,它同时也支持多种编程语言 ...
- 总结vue 需要掌握的知识点
使用的开发工具是webstorm,它是默认就安装好了vuejs插件,idea要使用的话,需要安装一下该插件 一.快速搭建项目vue-cli 脚手架(Vue2.0) 1.Vue CLI使用前提 –Nod ...
- ajax02_封装自己的jQuery库和ajax请求
封装自己的ajax类库 首先封装自己的 jQuery库 启发:css的元素选择器思想 简单的代码实现 function jQuery(selector){ if(typeof selector == ...
- 业务可视化-让你的流程图"Run"起来(3.分支选择&跨语言分布式运行节点)
前言 首先,感谢大家对上一篇文章[业务可视化-让你的流程图"Run"起来(2.问题与改进)]的支持. 分享一下近期我对这个项目的一些改进. 1. 增加了分支选择工程,可以根据节点的 ...
- [spring]spring的bean自动装配机制
7.bean的自动装配 是spring满足bean依赖的一种方式 spring会在上下文中自动寻找,并自动给bean装配属性 spring的装配方式: (1)手动装配 在people类中依赖了cat和 ...
- 心动不如行动,基于Docker安装关系型数据库PostgrelSQL替代Mysql
原文转载自「刘悦的技术博客」https://v3u.cn/a_id_171 最近"全栈数据库"的概念甚嚣尘上,主角就是PostgrelSQL,它最近这几年的技术发展不可谓不猛,覆盖 ...
- LyScript 内存交换与差异对比
LyScript 针对内存读写函数的封装功能并不多,只提供了内存读取和内存写入函数的封装,本篇文章将继续对API进行封装,实现一些在软件逆向分析中非常实用的功能,例如内存交换,内存区域对比,磁盘与内存 ...
- 技术分享 | load data导致主键丢失的神秘问题
欢迎来到 GreatSQL社区分享的MySQL技术文章,如有疑问或想学习的内容,可以在下方评论区留言,看到后会进行解答 GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源. 1 ...
- beego下让swagger按照更新了controllers的接口信息自动更新commentsRouter_controllers.go
beego下让swagger按照更新了controllers的接口信息自动更新commentsRouter_controllers.go (1)在beego环境中,当更新了controllers目录下 ...
- LuoguP1283 平板涂色(状压DP)
参考了I_AM_HelloWord的代码,\(f[i][j]\)表示转态\(i\)时最后一刷为\(j\)的最小代价,上面的块可用暴力填涂,注意边界 #include <cstdio> #i ...