question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. ItĀ collects links to all the places you might be looking at while hunting down a tough bug.

And, if youā€™re still stuck at the end, weā€™re happy to hop on a call to see how we can help out.

Jest memory problems in node environment

See original GitHub issue

šŸ’¬ Questions and Help

Stack:

  System:
    OS: macOS High Sierra 10.13.4
    CPU: x64 Intel(R) Core(TM) i7-4770HQ CPU @ 2.20GHz
  Binaries:
    Node: 8.1.4 - ~/.nvm/versions/node/v8.1.4/bin/node
    npm: 6.0.0 - ~/.nvm/versions/node/v8.1.4/bin/npm
  npmPackages:
    jest: ^23.0.1 => 23.0.1
    sequelize: ^4.37.10
    pg: ^7.4.3
    koa: ^2.3.0
    babel-jest: ^22.4.3

1. Preface

We recently switched all our APIā€™s test from Mocha to Jest. We have around 90 tests, half of them require to run synchronously due to them using our testing database (running seeds between them), so we have to use --runInBand.

I unfortunately canā€™t share my code as it is private.

2. The problem

Running tests one by one was fine, I then tried to run all of them at once and things went bad. With the --logHeapUsage, it seems context memory isnā€™t GCā€™d resulting in a Javascript heap out of memory.

I tried using the new option --detectOpenHandles to see what could prevent the GC to work but this is what came out:

  ā—  PROMISE
          at Promise.catch (<anonymous>)
      at node_modules/core-js/library/modules/es6.promise.js:244:30
      at Object.<anonymous>.module.exports (node_modules/core-js/library/modules/_iter-detect.js:19:5)
      at Object.<anonymous> (node_modules/core-js/library/modules/es6.promise.js:243:74)
      at Object.<anonymous> (node_modules/core-js/library/fn/promise.js:4:1)

I have around 6-8 of these, and no clue whatsoever of where to look.

I searched around and found out it was most likely the database connection so I added these as a global teardown:

afterAll(async () => {
    await db.close(); // Sequelize instance
    server.close(); // Koa server instance used with supertest (when needed)
});

This didnā€™t change much, memory still goes up very quickly (30-40 MB per test). In the end, I wrote a small file launching jest multiple times to avoid memory problems and stitching coverage report together but this isnā€™t ideal.

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Reactions:24
  • Comments:52 (2 by maintainers)

github_iconTop GitHub Comments

15reactions
lev-kazakovcommented, Jun 7, 2018

@rickhanlonii, Iā€™m also experiencing this bug, and I do suspect itā€™s a bug with jestā€™s module registry.

Jest does not cache modules as nodeā€™s require() does and probably does not release properly require()'d modules between test suites.

Created a repo to illustrate this issue.

10reactions
medikoocommented, Feb 16, 2019

@SimenB @cpojer @aaronabramov the source of the issue comes from fact that for every test run new modules cache is created but itā€™s used for all but native node.js modules.

On example of graceful-fs, following happens when more than one test is run within same process (or worker) as handled by Jest:

  1. (first test run) graceful-fs is freshly required and decorates native fs functions directly on fs object (note: through closures graceful-fs is permanently attached to fs and therefore cannot be freed)
  2. (second test run) graceful-fs is freshly required (again) within same process, and decorates (already decorated!) fs functions directly on fs object. Same way, itā€™s permanently attached to fs so not freed.

ā€¦ scenario repeats with every following test run.

So after a few test runs we deal with a situation, where after invoking single specific fs function, multiple graceful-fs functions are run recursively, and that I suppose is responsible for fastly growing memory leak.

Similarly popular Bluebird.promisifyAll(require('fs')) attaches to fs and introduces a leak. Still in that case itā€™s not recursive so not that harmful.

Iā€™ve noticed this when trying to incorporate long stack trace solution (based on async_hooks) into Jest, and observed how quickly it was blown with OOM, cause was that initializations were made before each test run, when there should be one initialization per process

When looking at Jest design, probably best solution would be to introduce an option in which we can list package names which should be handled by nodejs native modules loader (and graceful-fs could be there by default), so theyā€™re loaded once across all test runs within same process. As far as I see itā€™s not possible now, and that makes addressing this difficult.

Other solutions could be:

  • Provide an option to rely directly on require as provided by Node.js. It wonā€™t give desired isolation, but at least itā€™ll reflect public Node.js API, which is not respected with current approach.
  • Provide an option to run each test in its designated worker . Itā€™ll be slower, but itā€™s probably the only way to provide perfect side-effects free isolation.
Read more comments on GitHub >

github_iconTop Results From Across the Web

My Jests tests are leaking memory, how can I fix this?
First of all, make sure that you have leaky tests by running jest with the option: jest --logHeapUsage. Run your tests and check...
Read more >
Configuring Jest
Node.js core modules, like fs , are not mocked by default. They can be mocked explicitly, like jest.mock('fs')Ā ...
Read more >
Node.js Memory Leak Detection: How to Debug & Avoid Them
Some Node.js memory leaks are caused by common issues. These can be circular object references that are caused by a multitude of reasons....
Read more >
Debugging Memory Leaks in Node.js Applications - Toptal
Memory leaks in long running Node.js applications are like ticking time bombs that, if left unchecked in production environments, can result in devastatingĀ ......
Read more >
Finding And Fixing Node.js Memory Leaks: A Practical Guide
When Memory Leaks Become A Problem Ā· Restart Before It's Too Late Ā· Creating An Effective Test Environment Ā· Accessing Node. Ā· Taking...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found