Jest: Memory leak when using --coverage flag

Created on 12 Apr 2017  ยท  18Comments  ยท  Source: facebook/jest

bug

What is the current behavior?

When running our test suites with --coverage memory seems to leak, and heap size increases with ~13MB per test suite (we have a total of 240 test suites), ultimately causing Jest to slow down (as mentioned in other memory leak issues)

If the current behavior is a bug, please provide the steps to reproduce and either a repl.it demo through https://repl.it/languages/jest or a minimal repository on GitHub that we can yarn install and yarn test.

Unfortunately we can't provide the actual code from our tests, but all we have to do is enable --coverage to get the above behavior.

What is the expected behavior?

We would expect some overhead, but 13MB per test suite is causing our CI to timeout and make the coverage flag unusable.

Please provide your exact Jest configuration and mention your Jest, node, yarn/npm version and operating system.

[email protected], [email protected], [email protected], Mac OSX v10.12.3

  "jest": {
    "setupFiles": [
      "<rootDir>/src/setup.js"
    ],
    "setupTestFrameworkScriptFile": "<rootDir>/jest-setup.js",
    "roots": [
      "<rootDir>/src"
    ],
    "testEnvironment": "node",
    "testPathIgnorePatterns": [
      "/node_modules/"
    ],
    "coverageThreshold": {
      "global": {
        "branches": 60,
        "functions": 80,
        "lines": 80,
        "statements": 80
      }
    }
  }

I've masked the real path... so this is actually different files:

node --expose-gc $(BIN)/jest --no-cache --i --logHeapUsage

PASS  $/__tests__/test.js (71 MB heap size)
PASS  $/__tests__/test.js (71 MB heap size)
PASS  $/__tests__/test.js (71 MB heap size)
PASS  $/__tests__/test.js (71 MB heap size)
PASS  $/__tests__/test.js (71 MB heap size)
PASS  $/__tests__/test.js (71 MB heap size)
PASS  $/__tests__/test.js (71 MB heap size)
PASS  $/__tests__/test.js (72 MB heap size)
PASS  $/__tests__/test.js (72 MB heap size)
PASS  $/__tests__/test.js (71 MB heap size)
PASS  $/__tests__/test.js (74 MB heap size)
PASS  $/__tests__/test.js (71 MB heap size)
PASS  $/__tests__/test.js (72 MB heap size)
PASS  $/__tests__/test.js (78 MB heap size)
PASS  $/__tests__/test.js (78 MB heap size)

node --expose-gc $(BIN)/jest --coverage --no-cache --i --logHeapUsage

PASS  $/__tests__/test.js (139 MB heap size)
PASS  $/__tests__/test.js (151 MB heap size)
PASS  $/__tests__/test.js (164 MB heap size)
PASS  $/__tests__/test.js (177 MB heap size)
PASS  $/__tests__/test.js (189 MB heap size)
PASS  $/__tests__/test.js (202 MB heap size)
PASS  $/__tests__/test.js (215 MB heap size)
PASS  $/__tests__/test.js (228 MB heap size)
PASS  $/__tests__/test.js (240 MB heap size)
PASS  $/__tests__/test.js (253 MB heap size)
PASS  $/__tests__/test.js (265 MB heap size)
PASS  $/__tests__/test.js (278 MB heap size)
PASS  $/__tests__/test.js (291 MB heap size)
Confirmed Needs More Info

Most helpful comment

I'll try to make a small repro, but probably won't have the time before Tuesday.

All 18 comments

cc @bcoe

I can repro it with the Jest repo, although I get a similar behavior without --coverage

With coverage

โฏ node --expose-gc ./packages/jest-cli/bin/jest.js --coverage --no-cache --i --logHeapUsage packages
 PASS  packages/jest-util/src/__tests__/FakeTimers-test.js (55 MB heap size)
 PASS  packages/jest-matchers/src/__tests__/matchers-test.js (67 MB heap size)
 PASS  packages/jest-haste-map/src/__tests__/index-test.js (69 MB heap size)
 PASS  packages/jest-config/src/__tests__/normalize-test.js (71 MB heap size)
 PASS  packages/pretty-format/src/__tests__/ImmutablePlugins-test.js (78 MB heap size)
 PASS  packages/jest-mock/src/__tests__/jest-mock-test.js (81 MB heap size)
 PASS  packages/pretty-format/src/__tests__/React-test.js (85 MB heap size)
 PASS  packages/jest-cli/src/__tests__/SearchSource-test.js (92 MB heap size)
 ...
 ...
 ...
 PASS  packages/jest-editor-support/src/__tests__/parsers/BabylonParser-test.js (403 MB heap size)
 PASS  packages/jest-test-typescript-parser/src/__tests__/TypeScriptParser-test.js (420 MB heap size)
 PASS  packages/jest-resolve-dependencies/src/__tests__/__fixtures__/file-test.js (423 MB heap size)
 PASS  packages/jest-resolve-dependencies/src/__tests__/__fixtures__/related-test.js (425 MB heap size)
 PASS  packages/jest-jasmine2/src/__tests__/it_to_test_alias-test.js (424 MB heap size)

Without coverage

โฏ node --expose-gc ./packages/jest-cli/bin/jest.js --no-cache --i --logHeapUsage packages
 PASS  packages/jest-util/src/__tests__/FakeTimers-test.js (45 MB heap size)
 PASS  packages/jest-matchers/src/__tests__/matchers-test.js (47 MB heap size)
 PASS  packages/jest-haste-map/src/__tests__/index-test.js (43 MB heap size)
 PASS  packages/jest-config/src/__tests__/normalize-test.js (47 MB heap size)
 PASS  packages/pretty-format/src/__tests__/ImmutablePlugins-test.js (48 MB heap size)
 PASS  packages/jest-mock/src/__tests__/jest-mock-test.js (47 MB heap size)
 PASS  packages/pretty-format/src/__tests__/React-test.js (47 MB heap size)
 PASS  packages/jest-cli/src/__tests__/SearchSource-test.js (54 MB heap size)
 PASS  packages/pretty-format/src/__tests__/pretty-format-test.js (58 MB heap size)
 PASS  packages/jest-cli/src/reporters/__tests__/VerboseReporter-test.js (59 MB heap size)
 PASS  packages/jest-runtime/src/__tests__/transform-test.js (68 MB heap size)
 PASS  packages/jest-haste-map/src/crawlers/__tests__/watchman-test.js (71 MB heap size)
 ...
 ...
 ...
 PASS  packages/jest-editor-support/src/__tests__/parsers/BabylonParser-test.js (243 MB heap size)
 PASS  packages/jest-test-typescript-parser/src/__tests__/TypeScriptParser-test.js (256 MB heap size)
 PASS  packages/jest-resolve-dependencies/src/__tests__/__fixtures__/file-test.js (255 MB heap size)
 PASS  packages/jest-resolve-dependencies/src/__tests__/__fixtures__/related-test.js (254 MB heap size)
 PASS  packages/jest-jasmine2/src/__tests__/it_to_test_alias-test.js (251 MB heap size)

Can confirm this behaviour on Jest repo, although it doesn't happen on thousands of tests suite like that:

describe('test', function() {
  beforeAll(function() {
    global.gc();
  });

  it('work', function() {
    expect(1).toBe(1);
  });
});

@thymikee so you suggest that calling global.gc(); manually would be a workaround? I'll test in my repo

@danieljuhl @thymikee very curious about whether the gc helps, if so; I wonder if there's anything we can do on Istanbuljs' end.

@addaleax have you bumped into anything like this with Node's test suite?

I use gc for debugging just to be sure that there are no leftovers in memory. Please note it degrades perf A LOT.

Calling global.gc() is not a workaround and will not clean up memory leaks.

@thymikee @rogeliog @danieljuhl if we can get a fairly minimal reproduction, ideally exhibiting a minimal leak without coverage, and a leak with coverage, I'll happily use heapdump to do some investigating.

I'll try to make a small repro, but probably won't have the time before Tuesday.

@danieljuhl any updates? Can you also try if it happens on Jest 20?

I am facing the same problem, but the issue seems isolated to our CI environment. OP referenced this being unusable in CI, so I thought this might be helpful

https://discuss.circleci.com/t/memory-problems-with-jest-and-workers/10297

Obviously, if the issue exists in a local dev environment, then there is a larger memory issue. But thought this might be helpful.

Having the same issue with jest in Travis-CI, anyone have a workaround or a fix ? Might have to revert jest versions to bring things back in line.

@thymikee . Right now on Jest 20.0.4:
https://travis-ci.org/oshalygin/mdjs/builds/238230127

Note I have around 883 tests running right now, which doesnt seem like alot consider the gents at Facebook are well into the thousands.

Alright I was able to solve this(although not an ideal workaround) with this command:
"test:coverage": "jest --maxWorkers=1 --coverage",

Notice the --maxWorkers=1 flag.

Reference thread that helped:
https://github.com/facebook/jest/issues/1893

EDIT: Still having this issue, going to go down the route of closing the window right after jsdom.jsdom('') in my code

Okay solved the memory leak by removing any reference to jsdom.jsdom('') as part of my test suite. I am actually not using it at the moment so it's not a big issue, but if anyone is having this this might help.

@thymikee yep thanks! Your comment in that issue is exactly what led to my solution. I first closed the window object and things started working, then I thought to myself, "do I really need jsdom with my current test suite?" and then removed it altogether.

Thanks for the help!!

@danieljuhl any news on the repro?

We are reducing memory for coverage in Jest 21 (jest@test) but further leaks are probably not something we'll look at anytime soon. If you'd like to investigate further, please send us PRs with fixes :) Thank you.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

paularmstrong picture paularmstrong  ยท  3Comments

jardakotesovec picture jardakotesovec  ยท  3Comments

gustavjf picture gustavjf  ยท  3Comments

stephenlautier picture stephenlautier  ยท  3Comments

samzhang111 picture samzhang111  ยท  3Comments