{"id":13453925,"url":"https://github.com/andywer/leakage","last_synced_at":"2025-05-15T08:08:01.557Z","repository":{"id":40002837,"uuid":"77452964","full_name":"andywer/leakage","owner":"andywer","description":"🐛 Memory leak testing for node.","archived":false,"fork":false,"pushed_at":"2023-01-27T16:56:20.000Z","size":396,"stargazers_count":1583,"open_issues_count":10,"forks_count":52,"subscribers_count":15,"default_branch":"master","last_synced_at":"2025-04-07T02:19:36.659Z","etag":null,"topics":["javascript","memory-leak","nodejs","testing"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/andywer.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-12-27T12:12:16.000Z","updated_at":"2025-03-28T06:25:57.000Z","dependencies_parsed_at":"2023-02-15T11:00:37.137Z","dependency_job_id":null,"html_url":"https://github.com/andywer/leakage","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andywer%2Fleakage","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andywer%2Fleakage/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andywer%2Fleakage/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andywer%2Fleakage/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/andywer","download_url":"https://codeload.github.com/andywer/leakage/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248869142,"owners_count":21174821,"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":["javascript","memory-leak","nodejs","testing"],"created_at":"2024-07-31T08:00:49.346Z","updated_at":"2025-04-14T11:22:31.567Z","avatar_url":"https://github.com/andywer.png","language":"JavaScript","readme":"# Leakage - Memory Leak Testing for Node\n\n[![Build Status](https://travis-ci.org/andywer/leakage.svg?branch=master)](https://travis-ci.org/andywer/leakage) [![NPM Version](https://img.shields.io/npm/v/leakage.svg)](https://www.npmjs.com/package/leakage) [![JavaScript Style Guide](https://img.shields.io/badge/code%20style-standard-brightgreen.svg)](http://standardjs.com/)\n\nWrite leakage tests using Mocha or another test runner of your choice.\n\nDoes not only support spotting and fixing memory leaks, but writing tests also enables you to prevent regressions and show that the code does not leak.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg alt=\"Screencast\" width=\"600px\" src=\"https://github.com/andywer/leakage/raw/master/docs/failing-test.png?raw=true\" /\u003e\n\u003c/p\u003e\n\n\n## Table of Contents\n\n- [Installation](#installation)\n- [Usage](#usage)\n- [Memory Management in JS?](#memory-management-in-js)\n- [API](#api)\n- [Under the Hood](#under-the-hood)\n- [Travis CI](#travis-ci)\n- [FAQ](#faq)\n- [Contribute](#contribute)\n- [License](#license)\n\n\n## Installation\n\n```sh\nnpm install --save-dev leakage\n# or\nyarn --dev leakage\n```\n\n\n## Usage\n\nIn theory you could use any testing framework to run leakage tests. In practice, though, you want to use one that generates a minimal memory overhead itself. We suggest using Mocha or Tape, since they are quite simple and don't produce much noise in the captured data.\n\n### Usage with Mocha\n\n```js\nimport myLib from 'my-lib'\nimport { iterate } from 'leakage'\n\ndescribe('myLib', () =\u003e {\n  it('does not leak when doing stuff', () =\u003e {\n    iterate(() =\u003e {\n      const instance = myLib.createInstance()\n      instance.doStuff('foo', 'bar')\n    })\n  })\n})\n```\n\n`iterate()` will run the function several times, create a heap snapshot and repeat that process until there is a set of heap diffs. If a memory leak has been detected an error with some debugging information will be thrown.\n\n**Make sure you run all tests serially** in order to get clean heap diffs. Mocha should run them sequentially by default.\n\nUse `iterate.async()` for asynchronous test code. See [Asynchronous Tests](#asynchronous-tests) and [API](#api) for details.\n\n\n### Usage with tape\n\n```js\nimport test from 'tape'\nimport myLib from 'my-lib'\nimport { iterate } from 'leakage'\n\ntest('myLib does not leak when doing stuff', () =\u003e {\n  iterate(() =\u003e {\n    const instance = myLib.createInstance()\n    instance.doStuff('foo', 'bar')\n  })\n})\n```\n\n\n### Asynchronous Tests\n\nUse `iterate.async()` to test asynchronous code. The iterator function is supposed to return a promise and `iterate.async()` will return a promise itself. In case of a memory leak that returned promise will be rejected instead of `iterate` failing synchronously.\n\n*Do not forget to return the promise in your test or use async functions and `await iterate.async()`.*\n\n```js\nimport fetch from 'isomorphic-fetch'\nimport { iterate } from 'leakage'\n\ndescribe('isomorphic-fetch', () =\u003e {\n  it('does not leak when requesting data and parsing JSON', async () =\u003e {\n    await iterate.async(async () =\u003e {\n      const response = await fetch()\n      await response.json()\n    })\n  })\n})\n```\n\n\n## Memory Management in JS?\n\nSince every JavaScript runtime comes with a garbage collector you should not have to care about memory allocation / freeing memory at all, right? **Sadly not.**\n\nMemory leaks are a common problem in most programming languages. Memory gets allocated, but is not freed again, leading to a steadily increasing usage of memory. Since the memory you use is finite your application will eventually crash or become so slow it is rendered useless.\n\nAs soon as you still have a reference to an object, array, arrow function, ... you do not use anymore you might have already created a memory leak. Creating an object (incl. arrays and closures) means allocating heap memory that will be freed by the next automatic garbage collection only if all references to this object have vanished.\n\n\n## API\n\n### iterate(syncIterator: Function, options: ?Object): Result\n\nTest for memory leaks. Will throw an error when a leak is recognized.\n\n`syncIterator` can be any synchronous function. Let it perform your operations you want to test for memory leaks.\n\n`options.iterations` is the number the iterator function is run for each heap diff / garbage collection. Defaults to `30`.\n\n`options.gcollections` is the number of heap snapshots to create. Defaults to `60`.\n\n### iterate.async(asyncIterator: Function, options: ?Object): Promise\u003cResult\u003e\n\nTest for memory leaks. Will return a rejecting promise when a leak is recognized.\n\n`asyncIterator` can be any asynchronous function. Let it perform your operations you want to test for memory leaks.\n\n`options.iterations` is the number the iterator function is run for each heap diff / garbage collection. Defaults to `30`.\n\n`options.gcollections` is the number of heap snapshots to create. Defaults to `60`.\n\n### Result object\n\nProperties:\n* `heapDiffs` - An array of heap diffs as created by `node-memwatch`\n* `iterations` - The number of iterator runs per heap diff\n* `gcollections` - The number of garbage collections / heap diffs performed\n\nMethods:\n* `printSummary(title: ?String, log: ?Function)` - Prints a short summary. Can pass a title to print. `log` is the function used to output the summary line by line. Defaults to `console.log`.\n\n### MemoryLeakError\n\nMemory leak errors are instances of this custom error. You can use it to check if an error is really a memory leak error or just a generic kind of problem (like a broken reference).\n\nImport it as `const { MemoryLeakError } = require('leakage')`.\n\n\n### CLI Parameters\n\nYou can pass special CLI parameters for `leakage` to your test runner:\n\n```sh\nmocha test/sample.test.js --heap-file heap-diff.json\n```\n\n#### --heap-file \u003coutput file path\u003e\n\nWill make the library write a detailed heap diff JSON to the file system. Make sure you only run a single test using `it.only`. Otherwise you will only find the heap diff of the last test in the file. Useful for debugging.\n\n\n## Under the Hood\n\nLeakage uses `node-memwatch` to trigger the garbage collector and create heap diffs.\n\nYou just specify an iterator function. It will be run 30 times by default then a garbage collection will be performed and a heap snapshot will be made. This process is iterated 6 times by default to collect several heap diffs, since especially in async tests there is always a bit of background noise.\n\nIf the heap size increased over more than `[heapDiffCount * 2 / 3]` subsequent garbage collections an error is thrown.\n\n\n## Travis CI\n\nYou might want your leakage tests to be run by your CI service. There is an issue with Travis CI's linux containers, `g++` and a transitive dependency of `node-memwatch` ([nan](https://www.npmjs.com/package/nan)).\n\nFortunately there is a fix: You need to install and use version `4.8` of `g++` in order to compile the dependency.\n\nHave a look at leakage's [.travis.yml](./.travis.yml) file to see how it can be done or find further details by @btmills in this [issue](https://github.com/andywer/leakage/issues/4#issuecomment-269449814).\n\n\n## FAQ\n\n\u003cdetails\u003e\n\u003csummary\u003eI encountered a timeout error\u003c/summary\u003e\n\nIf you see an error like `Error: Timeout of 2000ms exceeded. (...)` it means that your test took so long that the test runner cancelled it.\n\nYou can easily increase the timeout. Have a look at your test runner's documentation for that. When using Mocha, for instance, you can run it with `--timeout 10000` to increase the timeout to 10000ms (10s).\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eWhy are my tests slow anyway?\u003c/summary\u003e\n\nLeakage tests are rather slow compared to usual unit tests, since heap snapshotting and diffing takes some time and has to be done several times per test.\n\nYou can try to reduce the number of heap diffs created, but beware that fewer heap diffs can result in less accurate results. See [API](#api) for details.\n\u003c/details\u003e\n\n\n## Contribute\n\nGot any feedback, suggestions, ...? Feel free to open an [issue](https://github.com/andywer/leakage/issues) and share your thoughts!\n\nUsed it successfully or were unable to use it? Let us know!\n\nHave an improvement? Open a pull request any time.\n\n\n## License\n\nReleased under the terms of the MIT license. See [LICENSE](./LICENSE) for details.\n","funding_links":[],"categories":["Packages","JavaScript","Repository","The Web Backend","包","目录","📦 Modules/Packages","Debugging / Profiling","Testing","Works with AVA"],"sub_categories":["Debugging / Profiling","Performance Profiling/Analysis","Testing","调试 / 分析","调试/分析","React Components","调试"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandywer%2Fleakage","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fandywer%2Fleakage","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandywer%2Fleakage/lists"}