jest: Jest memory problems in node environment
š¬ 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.
About this issue
- Original URL
- State: closed
- Created 6 years ago
- Reactions: 24
- Comments: 52 (15 by maintainers)
Commits related to this issue
- ci(all): run two integration tests at once to avoid memory leak issues See https://github.com/facebook/jest/issues/6399 for details. — committed to feature-hub/feature-hub by unstubbable 5 years ago
- ci(all): run two integration tests at once to avoid memory leak issues (#459) Jest with webpack has known memory leaks, see https://github.com/facebook/jest/issues/6399 for details. To put a bandaid ... — committed to feature-hub/feature-hub by unstubbable 5 years ago
- adds freezeCoreModules configuration option to mitigate memory leaks resolves #6399, resolves #6814 — committed to lev-kazakov/jest by lev-kazakov 5 years ago
- adds freezeCoreModules configuration option to mitigate memory leaks resolves #6399, resolves #6814 — committed to lev-kazakov/jest by lev-kazakov 5 years ago
- adds freezeCoreModules configuration option to mitigate memory leaks resolves #6399, resolves #6814 — committed to lev-kazakov/jest by lev-kazakov 5 years ago
- chore: update to latest graceful-fs This may fix memory leak running Jest tests. See https://github.com/facebook/jest/issues/6399#issuecomment-396338934 Signed-off-by: Eric Dobbertin <eric@dairystat... — committed to reactioncommerce/reaction by aldeed 5 years ago
- chore: update to latest graceful-fs This may fix memory leak running Jest tests. See https://github.com/facebook/jest/issues/6399#issuecomment-396338934 Signed-off-by: Eric Dobbertin <eric@dairystat... — committed to reactioncommerce/reaction by aldeed 5 years ago
- test: 'fix' memory leak in graceful-fs (#211) graceful-fs and jest does not like each other, so this removes the graceful-fs implementation before running tests and adds it back afterwards. https:... — committed to mikro-orm/mikro-orm by B4nan 5 years ago
@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 properlyrequire()
'd modules between test suites.Created a repo to illustrate this issue.
@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:graceful-fs
is freshly required and decorates nativefs
functions directly onfs
object (note: through closuresgraceful-fs
is permanently attached tofs
and therefore cannot be freed)graceful-fs
is freshly required (again) within same process, and decorates (already decorated!)fs
functions directly onfs
object. Same way, itās permanently attached tofs
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, multiplegraceful-fs
functions are run recursively, and that I suppose is responsible for fastly growing memory leak.Similarly popular
Bluebird.promisifyAll(require('fs'))
attaches tofs
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 processWhen 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:
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.This is something that only Jest could solve in the long run, relying on external authors to not do the bad thing (or even be aware of the issue) is just keeping a door open for this to happen again anyways in the future.
Is there something we could help on about this to make the matter advance?
@lev-kazakov @mrrinot Fixed the issue on our project by replacing
graceful-fs
withfs
when running the tests. (We change the file in thenode_modules
directory). It fixed the issue completely. We use this as a replacement:We put this inside
node_modules/graceful-fs/graceful-fs.js
when the tests start and we restore the ārealā version when they are done.It seems that graceful is only useful when you are on Windows. Since we donāt use Windows at all, we donāt need it.
@SimenB, Iāve sanitised a test case with no external dependencies: https://github.com/lev-kazakov/jest-leak/tree/master
If you run
yarn jasmine
, youāll see the memory is stabile around 7 Mb. If you runnode --expose-gc ./node_modules/.bin/jest --runInBand --logHeapUsage
, youāll see memory leaking.Memory leaks when you
require
code that overrides one of nodeās internal modules functions, while keeping a reference to the original function, like here.Libraries that do this kind of hacks:
Would you like me to open a new ticket?
Hi guys, is there any update on this?
Maybe coming with node 12 LTS and the worker modules? I have been bit hard by this issue yesterday and have been trying to find a solution since and still no luck š¢
I know that
graceful-fs
has been patched in4.1.12
but even by forcing the resolved version through yarn to4.1.15
I still face the issue so I suppose other packages in mynode_modules
are doing this.Sadly I donāt know of a good method to pinpoint those unless I spend a week on it and I canāt afford that right now.
Is there any update or plan for this in a near future?
@SimenB, @mrrinot ,
I think Iāve sanitised a test case that proves
graceful-fs
is not the issue, but rather itāsgraceful-fs
when required viajest
ās module registry.The following repo illustrates the issue: https://github.com/lev-kazakov/jest-leak/tree/master
If you run
yarn jasmine
, youāll see the memory is stabile around 7 Mb. If you runnode --expose-gc ./node_modules/.bin/jest --runInBand --logHeapUsage
, youāll see memory leaking.Note that Iām using the
import-fresh
module to bypassnode
ās cache when running withjasmine
.Here is a quick repro if you want: https://github.com/mrrinot/fs-extra-jest-repro After a more thorough test, it seems it is
graceful-fs
instead. Issues that seem related:It doesnāt seem that
graceful-fs
as of version4.1.15
has actually fixed the memory leak. Iāve forced npm to usegraceful-fs@4.1.15
throughout, but doing that my tests still leak memory like crazy and eventually crash. However, when I replacegraceful-fs/graceful-fs.js
with the replacement specified by @Telokis then my tests stop leaking memory and finish with no problem:I see a comment in
graceful-fs.js
source code where it seems like theyāve tried to stop leaking memory but clearly their fix is not working:@lev-kazakov Thanks. I removed the --verbose flag but the memory leak is still presentā¦
Guys, check if you have properly setup paths where JEST is scanning files for coverage. Iāve just discovered it goes to ādistā folder and this is causing memory looping - after excluding it everything works like a charm again.
@seyfer you can run your test suite against https://github.com/facebook/jest/pull/8331. run with
--freezeCoreModules
and--verbose
and it will smoke out the leaking modules. in order to run it against https://github.com/facebook/jest/pull/8331 you can either checkout the branch then build and linkjest
, or just hack your localnode_modules/jest-runtime/build/index.js
file with those changes: https://github.com/facebook/jest/pull/8331/files#diff-5b473ffb7e91f9fc070a6f6025790ef0 hereās an outdated but working patch for this matter: https://gist.github.com/sibelius/f98e62dd9346ddc97f07fe3814dc1b6e.Iād vote for implementing this first:
And then this:
@lev-kazakov I didnāt do anything except reporting here. @mrrinot did the work alone in our officeās cave.
yeah. anyhow iāve created a patcher inspired by @Telokis comment above. brute hack, but works. https://github.com/lev-kazakov/jest-leak-fixer.
Jest has built in
--logHeapUsage
, fwiwOk, turns out the problem comes from us importing fs-extra in one of our model. We use the latest version (6.0.1).
Just commenting the import fixes the memory going up between test suites. I donāt really know if itās a problem with fs-extra or jest.
Quick update:
I āsolvedā (more like put it under the rug) my issue by splitting the work done by jest beforehand.
find . -iname '*spec*' | grep -v node_modules | xargs -n 5 jest --no-cache --globalSetup ./test/globalSetup.js --forceExit
Of course this sucks because I canāt take advantage of concurrent testing, and my test suite takes forever, but at least it is able to run till the end.
Iām sorry to up this again, but do we have any updates on the matter?
itās
graceful-fs
: https://github.com/isaacs/node-graceful-fs/issues/102. @SimenB, fyi,jest
is also dependent ongraceful-fs
.Iām working on a reduced case of the problem, will get back to you when/if needed