{"id":13459616,"url":"https://github.com/facebook/memlab","last_synced_at":"2025-05-14T07:07:35.844Z","repository":{"id":47574549,"uuid":"496768943","full_name":"facebook/memlab","owner":"facebook","description":"A framework for finding JavaScript memory leaks and analyzing heap snapshots","archived":false,"fork":false,"pushed_at":"2025-05-07T01:44:20.000Z","size":29242,"stargazers_count":4539,"open_issues_count":11,"forks_count":129,"subscribers_count":39,"default_branch":"main","last_synced_at":"2025-05-07T06:38:33.554Z","etag":null,"topics":["detector","e2e","facebook","heap","hermes","javascript","leak","memory","nodejs","perf-tools","performance","snapshot","v8"],"latest_commit_sha":null,"homepage":"https://facebook.github.io/memlab/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/facebook.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2022-05-26T20:53:35.000Z","updated_at":"2025-05-07T02:54:48.000Z","dependencies_parsed_at":"2024-01-03T20:26:07.026Z","dependency_job_id":"c4e76e7e-9242-4ec0-862c-c43feb582678","html_url":"https://github.com/facebook/memlab","commit_stats":{"total_commits":375,"total_committers":20,"mean_commits":18.75,"dds":0.3813333333333333,"last_synced_commit":"b52e7dc228b2141a22456506ee6bd1df93aa4b77"},"previous_names":["facebookincubator/memlab"],"tags_count":27,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/facebook%2Fmemlab","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/facebook%2Fmemlab/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/facebook%2Fmemlab/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/facebook%2Fmemlab/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/facebook","download_url":"https://codeload.github.com/facebook/memlab/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254092648,"owners_count":22013290,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["detector","e2e","facebook","heap","hermes","javascript","leak","memory","nodejs","perf-tools","performance","snapshot","v8"],"created_at":"2024-07-31T10:00:22.849Z","updated_at":"2025-05-14T07:07:35.792Z","avatar_url":"https://github.com/facebook.png","language":"JavaScript","readme":"\u003ch1 align=\"center\"\u003e\n  \u003ca href=\"https://facebook.github.io/memlab/\"\u003eMemLab\u003c/a\u003e\n\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/facebook/memlab/blob/master/LICENSE\"\u003e\n    \u003cimg alt=\"Licensed under the MIT License\" src=\"https://img.shields.io/badge/License-MIT-blue.svg\"/\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/facebook/memlab/blob/main/CONTRIBUTING.md\"\u003e\n    \u003cimg alt=\"PR's Welcome\" src=\"https://img.shields.io/badge/PRs%20-welcome-brightgreen.svg\"/\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://www.npmjs.com/package/memlab?activeTab=readme\"\u003e\n    \u003cimg alt=\"npm version\" src=\"https://img.shields.io/npm/v/memlab.svg?style=flat\"/\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\nmemlab is an end-to-end testing and analysis framework for identifying\nJavaScript memory leaks and optimization opportunities.\n\n**Online Resources:** [[Website and Demo](https://facebook.github.io/memlab)] | [[Documentation](https://facebook.github.io/memlab/docs/intro)] | [[Meta Engineering Blog Post](https://engineering.fb.com/2022/09/12/open-source/memlab/)]\n\nFeatures:\n\n- **Browser memory leak detection** - Write test scenarios with the Puppeteer\n  API, and memlab will automatically compare JavaScript heap snapshots, filter\n  out memory leaks, and aggregate the results\n- **Object-oriented heap traversing API** - Supports the creation of\n  self-defined memory leak detector, and enables programmatic analysis JS heap\n  snapshots taken from Chromium-based browsers, Node.js, Electron.js, and Hermes\n- **Memory CLI toolbox** - Built-in toolbox and APIs for finding memory\n  optimization opportunities (not necessarily just memory leaks)\n- **Memory assertions in Node.js** - Enables unit tests or running node.js\n  programs to take a heap snapshot of their own state, perform self memory\n  checking, or write advanced memory assertions\n\n![](./website/static/img/heap-diff.gif)\n\n## CLI Usage\n\nInstall the CLI\n\n```bash\nnpm install -g memlab\n```\n\n### Find Memory Leaks\n\nTo find memory leaks in Google Maps, you can create a\n[scenario file](https://facebook.github.io/memlab/docs/api/interfaces/core_src.IScenario) defining how\nto interact with the Google Maps, let's name it `test-google-maps.js`:\n\n```javascript\n// initial page load url: Google Maps\nfunction url() {\n  return 'https://www.google.com/maps/@37.386427,-122.0428214,11z';\n}\n\n// action where we want to detect memory leaks: click the Hotels button\nasync function action(page) {\n  // puppeteer page API\n  await page.click('text/Hotels');\n}\n\n// action where we want to go back to the step before: click clear search\nasync function back(page) {\n  // puppeteer page API\n  await page.click('[aria-label=\"Close\"]');\n}\n\nmodule.exports = {action, back, url};\n```\n\nNow run memlab with the scenario file, memlab will interact with\nthe web page and detect memory leaks with built-in leak detectors:\n\n```bash\nmemlab run --scenario test-google-maps.js\n```\n\nmemlab will print memory leak results showing one representative\nretainer trace for each cluster of leaked objects.\n\n**Retainer traces**: This is the result from\n[an example website](https://facebook.github.io/memlab/docs/guides/guides-find-leaks),\nthe retainer trace is an object reference chain from the GC root to a leaked\nobject. The trace shows why and how a leaked object is still kept alive in\nmemory. Breaking the reference chain means the leaked object will no longer\nbe reachable from the GC root, and therefore can be garbage collected.\nBy following the leak trace one step at a time, you will be able to find\na reference that should be set to null (but it wasn't due to a bug).\n\n```bash\nMemLab found 46 leak(s)\n--Similar leaks in this run: 4--\n--Retained size of leaked objects: 8.3MB--\n[Window] (native) @35847 [8.3MB]\n  --20 (element)---\u003e  [InternalNode] (native) @130981728 [8.3MB]\n  --8 (element)---\u003e  [InternalNode] (native) @130980288 [8.3MB]\n  --1 (element)---\u003e  [EventListener] (native) @131009888 [8.3MB]\n  --1 (element)---\u003e  [V8EventListener] (native) @224808192 [8.3MB]\n  --1 (element)---\u003e  [eventHandler] (closure) @168079 [8.3MB]\n  --context (internal)---\u003e  [\u003cfunction scope\u003e] (object) @181905 [8.3MB]\n  --bigArray (variable)---\u003e  [Array] (object) @182925 [8.3MB]\n  --elements (internal)---\u003e  [(object elements)] (array) @182929 [8.3MB]\n...\n```\n\nTo get readable trace, the web site under test needs to serve non-minified code (or at least minified code\nwith readable variables, function name, and property names on objects).\n\nAlternatively, you can debug the leak by loading the heap snapshot taken by memlab (saved in `$(memlab get-default-work-dir)/data/cur`)\nin Chrome DevTool and search for the leaked object ID (`@182929`).\n\n**View Retainer Trace Interactively**\n\nView memory issues detected by memlab based on a single JavaScript\nheap snapshot taken from Chromium, Hermes, memlab, or any node.js\nor Electron.js program:\n\n```bash\nmemlab view-heap --snapshot \u003cPATH TO .heapsnapshot FILE\u003e\n```\n\nYou can optionally specify a specific heap object with the object's id: `--node-id @28173` to pinpoint a specific object.\n\n![heap-view](./website/static/img/heap-view.png)\n\n**Self-defined leak detector**: If you want to use a self-defined leak detector, add a `leakFilter` callback\n([doc](https://facebook.github.io/memlab/docs/api/interfaces/core_src.IScenario/#-optional-leakfilter-leakfiltercallback))\nin the scenario file. `leakFilter` will be called for every unreleased heap\nobject (`node`) allocated by the target interaction.\n\n```javascript\nfunction leakFilter(node, heap) {\n  // ... your leak detector logic\n  // return true to mark the node as a memory leak\n}\n```\n\n`heap` is the graph representation of the final JavaScript heap snapshot.\nFor more details, view the\n[doc site](https://facebook.github.io/memlab/docs/api/interfaces/core_src.IHeapSnapshot).\n\n### Heap Analysis and Investigation\n\nView which object keeps growing in size during interaction in the previous run:\n\n```bash\nmemlab analyze unbound-object\n```\n\nAnalyze pre-fetched V8/hermes `.heapsnapshot` files:\n\n```bash\nmemlab analyze unbound-object --snapshot-dir \u003cDIR_OF_SNAPSHOT_FILES\u003e\n```\n\nUse `memlab analyze` to view all built-in memory analyses.\nFor extension, view the [doc site](https://facebook.github.io/memlab).\n\nView retainer trace of a particular object:\n\n```bash\nmemlab trace --node-id \u003cHEAP_OBJECT_ID\u003e\n```\n\nUse `memlab help` to view all CLI commands.\n\n## APIs\n\nUse the `memlab` npm package to start a E2E run in browser and detect memory leaks.\n\n```javascript\nconst memlab = require('memlab');\n\nconst scenario = {\n  // initial page load url\n  url: () =\u003e 'https://www.google.com/maps/@37.386427,-122.0428214,11z',\n\n  // action where we want to detect memory leaks\n  action: async page =\u003e await page.click('text/Hotels'),\n\n  // action where we want to go back to the step before\n  back: async page =\u003e await page.click('[aria-label=\"Close\"]'),\n};\nmemlab.run({scenario});\n```\n\n## Memory Assertions\n\nmemlab makes it possible to enable a unit test or running node.js program\nto take a heap snapshot of its own state, and write advanced memory assertions:\n\n```typescript\n// save as example.test.ts\nimport type {IHeapSnapshot, Nullable} from '@memlab/core';\nimport {config, takeNodeMinimalHeap} from '@memlab/core';\n\nclass TestObject {\n  public arr1 = [1, 2, 3];\n  public arr2 = ['1', '2', '3'];\n}\n\ntest('memory test with heap assertion', async () =\u003e {\n  config.muteConsole = true; // no console output\n\n  let obj: Nullable\u003cTestObject\u003e = new TestObject();\n  // get a heap snapshot of the current program state\n  let heap: IHeapSnapshot = await takeNodeMinimalHeap();\n\n  // call some function that may add references to obj\n  rabbitHole(obj);\n\n  expect(heap.hasObjectWithClassName('TestObject')).toBe(true);\n  obj = null;\n\n  heap = await takeNodeMinimalHeap();\n  // if rabbitHole does not have any side effect that\n  // adds new references to obj, then obj can be GCed\n  expect(heap.hasObjectWithClassName('TestObject')).toBe(false);\n}, 30000);\n```\n\nFor other APIs check out the\n[API documentation](https://facebook.github.io/memlab/docs/api/interfaces/core_src.IHeapSnapshot#hasobjectwithclassnameclassname).\n\n## Development\n\nUse node version 16 or above. To build on Windows, please use Git Bash.\n\nFirst build the project as follows:\n\n```bash\nnpm install\nnpm run build\n```\n\nThen keep this helper script running to ensure that local changes are picked up\nand compiled automatically during development:\n\n```bash\nnpm run dev\n```\n\nNOTE: To run the memlab cli locally, make sure to prefix the memlab command with\nnpx from within the memlab repo e.g. `npx memlab`\n\nRun tests:\n\n```bash\nnpm run test\n```\n\n## License\n\nmemlab is MIT licensed, as found in the [LICENSE](LICENSE) file.\n\n## Contributing\n\nCheck our [contributing guide](CONTRIBUTING.md) to learn about how to\ncontribute to the project.\n\n## Code of Conduct\n\nCheck our [Code Of Conduct](CODE_OF_CONDUCT.md) to learn more about our\ncontributor standards and expectations.\n","funding_links":[],"categories":["JavaScript","facebook","TypeScript","语言资源库","JavaScript框架"],"sub_categories":["typescript","大语言对话模型及数据"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffacebook%2Fmemlab","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffacebook%2Fmemlab","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffacebook%2Fmemlab/lists"}