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 leaks memory from required modules with closures over imports

See original GitHub issue

šŸ› Bug Report

We are running into a issue in Jest 23.4.2 where Jest leaks and runs out of memory when running a moderately hefty test suite (~500 to 1000 test files). I believe I have isolated this to the require system in Jest and it is not the fault of other packages. Even with the most minimal recreation it leaks around 2-6MB per test.

This is very similar to https://github.com/facebook/jest/issues/6399 but I opted to make a new issue as I think itā€™s not specific to packages or the node environment. I think itā€™s the also the source or related to the following issues as well but didnā€™t want to sidetrack potentially different issues and conversations.

https://github.com/facebook/jest/issues/6738 https://github.com/facebook/jest/issues/6751 https://github.com/facebook/jest/issues/5837 https://github.com/facebook/jest/issues/2179

This is my first time digging into memory issues, so please forgive me if I am focusing on the wrong things!

Link to repl or repo

I have created a very minimal reproduction here: https://github.com/pk-nb/jest-memory-leak-repro. You should be able to run and see heap grow and also debug it with the chrome node devtools. With the reproduction, we can see this happens in both JSDOM and node environments in Jest.

screen shot 2018-08-07 at 7 43 02 pm screen shot 2018-08-07 at 6 49 44 pm

To Reproduce

Simply run a test suite with tests that require in a file that creates a closure over an imported variable:

// sourceThatLeaks.js

const https = require('https');

let originalHttpsRequest = https.request;

https.request = (options, cb) => {
  return originalHttpsRequest.call(https, options, cb);
};

// If this is uncommented, the leak goes away!
// originalHttpsRequest = null;
// 1.test.js, 2.test.js, ...

require("./sourceThatLeaks");

it("leaks memory", () => {});

While every worker leaks memory and will eventually run out, it is easiest to see with --runInBand.

Note that we are not doing anything with require to force a reimportā€”this is a vanilla require in each test.

When run with jasmine, we can see the issue go away as there is no custom require implementation for mocking code. We also see the issue disappear if we release the variable reference for GC by setting to null.

I believe the closure is capturing the entire test context (which also includes other imports like jest-snapshots) which quickly adds up.

Expected behavior

Hoping to fix so there is no leak. This unfortunately is preventing us from moving to Jest as we cannot run the suite on our memory bound CI (even with multiple workers to try to spread the leak).

Iā€™m hoping the reproduction is usefulā€”I spent some time trying to fix with some basic guesses at closures but ultimately am in over my head with the codebase.

You can see the huge closure in the memory analysis so Iā€™m inclined to think itā€™s some closure capture over the require implementation and/or the jasmine async function (promise).

screen shot 2018-08-07 at 6 52 50 pm screen shot 2018-08-07 at 4 45 32 pm screen shot 2018-08-07 at 7 13 23 pm

Some leak suspects:

These are educated guesses, but there are quite a few closures within the runtime / runner / jasmine packages though so itā€™s very difficult (as least for me being new to the codebase) to pinpoint where the capture lies. Iā€™m hoping that thereā€™s a specific point and that each closure in the runtime would not present the same issue.

Our suite

I have ensured the issue stems from Jest and not our suiteā€”I ran the old suite (mocha) and saw a healthy sawtooth usage of heap.

Run npx envinfo --preset jest

ā–² npx envinfo --preset jest
npx: installed 1 in 2.206s

  System:
    OS: macOS High Sierra 10.13.6
    CPU: x64 Intel(R) Core(TM) i9-8950HK CPU @ 2.90GHz
  Binaries:
    Node: 8.11.3 - ~/.nodenv/versions/8.11.3/bin/node
    Yarn: 1.9.4 - ~/.nodenv/versions/8.11.3/bin/yarn
    npm: 5.6.0 - ~/.nodenv/versions/8.11.3/bin/npm
  npmPackages:
    jest: ^23.4.2 => 23.4.2

Please let me know if I can help in any way! Iā€™d really love to get our company on Jest and am happy to help where I can. Thanks @lev-kazakov for the original isolation repro.

Issue Analytics

  • State:open
  • Created 5 years ago
  • Reactions:112
  • Comments:33 (7 by maintainers)

github_iconTop GitHub Comments

15reactions
oskarolscommented, Aug 27, 2022

@SimenB If itā€™s innate to the implementation of Jest that a lot of larger code bases might run into these problems then I think it would be very helpful to actually have more details in the docs on why this would happen and common ways of debugging it (beyond the existing CLI args).

As it currently stands thereā€™s not a lot of detail on how the module loading works in the docs. And thatā€™s understandable in the sense that users ā€œshouldnā€™t have to know how it worksā€. However if it is the case that having somewhat of an understanding of at least the general working of Jest can help users write more performant tests and understand why memory leaks can easy become an issue, then itā€™s perhaps worth reconsidering.

13reactions
kirillgroshkovcommented, Mar 25, 2019

any updates? We still face memory leaks from time to time, especially in a memory-constrained CI environment (leaks add up and crash at some point)

Read more comments on GitHub >

github_iconTop Results From Across the Web

Your Jest Tests are Leaking Memory
In this article, we'll walk through why it's so easy for Jest to leak memory, how to tell if your tests have a...
Read more >
Why is memory leaking in component tests (Jest with React ...
I have React components and i use React Testing Library and jest for testing them. I tried to debug them with this command...
Read more >
Causes of Memory Leaks in JavaScript and How to Avoid Them
A memory leak occurs when an object in memory that is supposed to be cleaned in a garbage collection cycle stays reachable from...
Read more >
Hunting memory leaks in a server side rendered React ...
We are working with an environment where we should handle 5 renders per 1 second on one pod of our NodeJS server side...
Read more >
MemLab: An open source framework for finding JavaScript ...
JavaScript code can experience memory leaks by keeping hidden references to objects. Hidden references can cause memory leaks in many unexpectedĀ ...
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