emlab,一款分析 JavaScript 堆并查找浏览器和 Node.js 中内存泄漏的开源框架 原创 为少 黑客下午茶
时间:2023-03-12 10:56:01
科技观察
emlab,一个开源框架,用于分析JavaScript堆并查找浏览器和Node.jsChance中的内存泄漏。Memlab是JavaScript的内存测试框架。它支持定义测试场景(使??用PuppeteerAPI),教Memlab如何与您的单页应用程序(SPA)交互,Memlab可以自动处理其余的内存泄漏检查:与浏览器交互并获取用于分析的JavaScript堆快照堆快照并过滤掉内存泄漏聚合和分组类似的内存泄漏生成用于内存调试的保留跟踪安装Memlabnpminstall-gmemlabmemlabhelpDetectDemoApp中的泄漏使用MemlabTutorial检测分离的DOM元素。演示源代码:https://github.com/facebookincubator/memlab/tree/main/packages/e2e/static/example设置示例Web应用程序当您单击“创建分离的DOM”按钮时,演示应用程序将泄漏分离DOM元素。每次单击都会创建1024个单独的DOM元素,这些元素由window对象引用。//@nolintimport从'next/link'链接;从'react'导入React;导出默认函数DetachedDom(){constaddNewItem=()=>{if(!window.leakedObjects){window.leakedObjects=[];}for(leti=0;i<1024;i++){window.leakedObjects.push(document.createElement('div'));}console.log('已创建分离的DOM。请检查devtools中的“内存”选项卡')};return(返回
CreatedetachedDOMs );}源文件:packages/e2e/static/example/pages/examples/detached-dom.jsx1。克隆存储库要在本地计算机上运行演示,请克隆memlabgithub存储库:https://github.com/facebookincubator/memlabgitclonegit@github.com:facebookincubator/memlab.git2.运行示例应用程序从Memlab项目的根目录运行以下命令:cdpackages/e2e/static/examplenpminstallnpmrundev这将启动一个示例Nextjsapp让我们通过访问http://localhost确保它正在运行:3000从浏览器运行:这里测试示例1。查找内存泄漏1.创建一个场景文件//@nolint//memlab/packages/e2e/static/example/scenario/detached-dom.js/***我们要运行的场景的初始`url`。*/functionurl(){return"http://localhost:3000/examples/detached-dom";}/***指定memlab在导致内存泄漏时应如何执行您要测试的操作。**@parampage-Puppeteer的页面对象:*https://pptr.dev/api/puppeteer.page/*/asyncfunctionaction(page){constelements=awaitpage.$x("//button[contains(.,'创建分离的DOM')]");const[按钮]=元素;如果(按钮){awaitbutton.click();}//从memlab中清除外部引用awaitPromise.all(elements.map(e=>e.dispose()));}/***指定memlab应如何执行将重置您在上面执行的操作的操作。**@parampage-Puppeteer的页面对象:*https://pptr.dev/api/puppeteer.page/*/asyncfunctionback(page){awaitpage.click('a[href="/"]');}module.exports={动作,返回,url};该文件位于packages/e2e/static/example/scenario/detached-dom.js中。2.运行memlab这可能需要几分钟:cdpackages/e2e/static/examplenpmrundev#NotestartDemomemlabrun--scenarioscenarios/detached-dom.js3.调试泄漏跟踪对于每个泄漏的对象组,memLab打印一个代表性泄漏痕迹。让我们从上到下分解结果:第1部分:浏览器交互面包屑显示按照我们的场景文件中指定执行的浏览器交互(导航)memlab。page-load[6.5MB](baseline)[s1]-初始页面加载时JavaScript堆大小为6.5MB。基线堆快照将作为s1.heapsnapshot保存在磁盘上。action-on-page[6.6MB](baseline)[s2]-点击“CreatedetachedDOMs”按钮后,堆大小增加到6.6MB。revert[7MB](final)[s3]-离开触发内存泄漏的页面后,页面最终达到7MB。第2部分:泄漏跟踪1024次泄漏的总体总结-具有1024次泄漏的对象。示例应用程序的第12行在for循环中创建了1024个分离的DOM对象。保留大小——泄漏对象集群的总保留大小为143.3KB(内存泄漏根据保留痕迹的相似性分组在一起)。第3部分:每个泄漏簇的详细代表性泄漏跟踪泄漏跟踪是从GC根(垃圾收集器遍历堆的堆图中的入口对象)到泄漏对象的对象引用链。跟踪显示泄漏的对象为何以及如何在内存中仍然存在。打破引用链意味着泄漏的对象将不再可以从GC根访问,因此可以被垃圾收集。通过从本机Window(即GC根)逐步减少泄漏跟踪,您将能够找到应设置为null的引用(但这不是由于错误)。map-这是被访问对象的V8HiddenClass(V8在内部使用它来存储关于对象形状的元信息和对其原型的引用-在此处查看更多信息)-在大多数情况下,这是V8实现细节,可以忽略.https://v8.dev/blog/fast-properties#hiddenclasses-and-descriptorarraysprototype-这是Window类的一个实例。leakedObjects-这表明leakedObjects是Window对象的一个??属性,大小为148.5KB,指向一个Array对象。0-这表示一个分离的HTMLDIVElement(即当前未连接到DOM树的DOM元素)被存储为leakedObjects数组的第一个元素(由于显示所有1024个泄漏痕迹是压倒性的,Memlab只打印有代表性的leaktrace。即property0而不是property0->1023)简而言之,从Window对象到泄漏对象的leaktrace路径为:[window](object)->leakedObjects(property)->[Array](object)->0(element)->[DetachedHTMLDIVElement](native)匹配示例中泄露的代码:window.leakedObjects=[];for(leti=0;i<1024;i++){窗户。泄露的对象。推送(document.createElement('div'));}