Meta开源JavaScript内存泄漏监测工具MemLab

标签: meta 开源 javascript | 发表时间:2022-09-22 11:26 | 作者:xiangzhihong
出处:https://juejin.cn/frontend

一、MemLab简介

上周,Facebook母公司Meta 宣布了开源 MemLab,一个基于 Chromium 的浏览器的 JavaScript 应用程序内存泄漏监测工具。同时,Facebook 技术团队指出:“应用程序的性能和功能正确性问题通常会被用户立即留意到。然而内存泄漏却不一样,它不容易被立即察觉,但它每次都会吃掉一大块内存,使得整个网络会话的响应变得非常慢。”

为了帮助开发人员解决这个问题,Meta 构建了MemLab,它可以自动进行内存泄漏检测并更容易找到泄漏的根本原因。据官方公告称,Meta 内部使用它成功地控制了不可持续的内存增长,并识别了产品和基础设施中的内存泄漏和内存优化机会。目前,Meta 已经在 GitHub 上开源了 MemLab。

image.png

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 的工作方式就是导航到一个页面、然后离开。正常情况下,可预计该页面分配的大部分内存也将被释放。但若没有被释放,则意味其存在极高的内存泄露可能性。

image.png   我们知道,React 使用存储在树结构中、被称作 Fibers 的对象,来表示内存中的浏览器文档对象模型(DOM)。据该团队所述,这可能是存在“巨大内存泄露”的一个主要原因。拥有强连接图的缺点很是显著,若有任何外部引用指向图的任何部分,就无法对整个图开展垃圾回收。

对于浏览器内存泄漏检测,MemLab 需要开发人员提供的唯一输入是一个测试场景文件,该文件定义了如何通过 overriding Puppeteer API 和 CSS 选择器的三个回调来与网页进行交互。MemLab 会自动对 JavaScript heap 进行差异化处理,完善内存泄漏,并对结果进行汇总。

MemLab-figure-2-FINAL.gif

MemLab 的另一特性,就是提供了 JavaScript 堆的图形视图、启用了用于检查堆快照的 API 。这意味着开发者能够编写开展内存断言的测试,例如声明某个对象将不再存在于内存中。

image.png

此外还有一个用于查找重复字符串实例的工具,在某个案例中,团队发现字符串占用了 70% 的堆、且其中半数至少有一个重复的实例。包括 Chrome、Edge、Firefox 在内的浏览器,都有附带内存检查工具。但正如以为开发者在 Hacker News 上吐槽的那样,这些开发工具难以在调试过程中揪出内存泄露的问题。

image.png 最后,MemLab 的另一项强大功能,就是可以在测试期间作为命令过程的一部分而运行。这意味着如果代码中引入了严重的泄露,开发者们也能够在投入生产环境前加以捕获。

除了内存泄漏检测之外,MemLab还包括一组用于查找内存优化机会的内置CLI命令和api,并提供如下的功能:

  • 堆内容分解
  • 监测单个对象的内存使用情况
  • 查找重复的字符串实例

比如,监测浏览内存泄漏部分UI。

image.png

跟踪UI内存泄漏的整个链路。

image.png

三、基本使用

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来精确定位特定的堆对象。

image.png

当然,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);

附件: https://github.com/facebookincubator/memlab

相关 [meta 开源 javascript] 推荐:

Meta开源JavaScript内存泄漏监测工具MemLab

- - 掘金 前端
上周,Facebook母公司Meta 宣布了开源 MemLab,一个基于 Chromium 的浏览器的 JavaScript 应用程序内存泄漏监测工具. 同时,Facebook 技术团队指出:“应用程序的性能和功能正确性问题通常会被用户立即留意到. 然而内存泄漏却不一样,它不容易被立即察觉,但它每次都会吃掉一大块内存,使得整个网络会话的响应变得非常慢.

eBay将其JavaScript IDE开源 — eBay Tech Blog

- 競 - J道jdon.com
eBay Open Sourced its JavaScript IDE — eBay Tech Blog VJET优点: 1.Javascript编程更快,有代码自动完成 代码模板和导向.

Meta 透露元宇宙 AI 项目

- - 奇客Solidot–传递最新科技情报
Facebook 母公司Meta 首席执行官扎克伯格周三 表示,公司正在进行人工智能(AI)研究,以通过语音生成世界,改进人们与语音助手的聊天方式,并在不同语言之间进行翻译. 他勾勒出了建立元宇宙的关键步骤. 扎克伯格押注元宇宙将接替移动互联网. 元宇宙是一个未来主义的想法,即用户可以在其中工作、社交和游戏的虚拟环境.

Google开源ScriptCover,JavaScript代码覆盖率工具

- Tim - ITeye资讯频道
Google已经宣布ScriptCover将作为一个开源项目发布. ScriptCover是Google推出的一款JavaScript代码覆盖率分析工具,为Web页面提供实时、逐行的代码覆盖分析. Google表示,ScriptCover最终将应用在Chrome浏览器上成为它的一个扩展. ScriptCover的测试结果将显示在一个持续加载的页面上,在用户操作网站时它会自动更新.

Testacular:Google开源的JavaScript测试执行过程管理工具

- - 博客 - 伯乐在线
Google 已开源  Testacular,一个基于 Node.js 的 JavaScript 测试执行过程管理工具(Test Runner). 该工具可用于测试所有主流Web 浏览器,也可集成到 CI (Continuous integration)工具,也可和其他代码编辑器一起使用. Testacular 可以在不同的桌面或移动设备浏览器上,或在持续集成的服务器上测试 JavaScript 代码.

开发者不容错过的12款开源JavaScript库

- - ITeye资讯频道
JavaScipt几乎是所有前端开发人员必会的编程语言,并且,随着各种移动APP的串红,JavaScript还可以用来开发移动应用. 除此以外,为了丰富前端/移动开发,有不少开发者推出了各种基于JavaScript的库,这些几乎能实现任何你需要的功能,并且有些库可以用来开发某些特定的功能,非常强大.

原生体验挡不住!JavaScript开源跨平台框架NativeScript

- - 博客园_新闻
NativeScript 是一款使用 JavaScript 语言来构建跨平台原生移动应用的开源框架,支持 iOS、Android 和 Windows Phone. 且 NativeScript 的使用没有过多繁杂的要求,只需使用自己已经掌握的 JavaScript 和 CSS 技能就能开发出真正具有原生用户体验的移动应用.

Meta Watch通过FCC认证 售价199美金

- 乌鸦 - cnBeta.COM
感谢@Android安卓星空 .的投递. Android迷翘首以盼的Fossil Meta Watch是一拖再拖,今天外媒终于传来了好消息,这款手表已经通过了FCC的认证,接下来它就可以同步到您的Android智能手机或平板电脑了. 手表有两个版本,一个为指针式,有标准的旋钮以及两个小型OLED显示屏;另一个版本为数字式.

Meta 宣布文本视频生成器 Make-A-Video

- - 奇客Solidot–传递最新科技情报
在文本图像生成器流行之后,Meta 宣布了文本视频生成器 Make-A-Video,可通过文本或图像提示生成视频内容. Meta 演示了利用一段文字描述或一幅静态图像生成视频的效果,比如一幅海龟图像在处理之后变成了海龟游泳视频. Make-A-Video 是基于现有的文本图像生成模型,如 OpenAI 的 DALL-E.

Yahoo!开源Mojito,一款承诺“编写一次,到处运行”的JavaScript框架

- - InfoQ cn
开源其 Mojito——一款用来创建可重用微件(widget)的框架,能在各种web应用中使用,且无需修改代码就能在客户端或服务器端运行. 继不久前刚开源了 YSlow,Yahoo. 已决定再对 Mojito开源,这是一款用于构建MVC web应用的JavaScript web框架. Cocktails的一部分,这款JavaScript平台,它所开发的web应用代码能够运行在多种设备——如PC机、平板电脑、智能手机等——无需考虑每种设备的外观因素去修改代码.