-
-
Notifications
You must be signed in to change notification settings - Fork 6.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Memory allocation failure when running lots of tests with --runInBand in limited env (Travis) #2179
Comments
Hey! I'm sorry I'm just getting back from a vacation and am pretty swamped. Please note that all of this is on top of my mind and I'll get back to it soon but it may take a bit more than a week until I can dedicate real time for this. I'm sure we can fix most of these issues. |
@cpojer 👍 I'm just trying to document what I can while it's on my mind. Good luck catching up after vacation! |
Thanks! I really appreciate that you are doing this – if you can find any significant problems inside of Jest that we can turn into a PR, that would definitely make this process faster. Jest doesn't do well on resource capped machines (low memory/low cpu/slow disk access) and things like code coverage generate a ton of data. Generally we don't have the same kind of issues you are experiencing with Facebook's projects that also use Travis, so we'll have to figure out what's going on. |
Hi, @cpojer I just faced the same kind of issue with a slow test run with Tested on my recent Mac Book Pro locally but not on any CI environment yet. comments:
I may have done something wrong tho. P.S: it runs a Hope it helps :) |
I see similar things in Travis:
This log comes from a test that uses it('should show the VIP header when isVip is true', function () {
let props = Object.assign({}, DEFAULT_PROPS, {isVip: true});
element = mountWithIntl(<WelcomeVoucherModal {...props} />);
let header = element.ref('header');
expect(header.find({id: 'settings.welcomeVipPlusMember'})).toBeTruthy();
}); I've got ~1800 tests running and it this log always appears during the last two tests. Here's the command I'm running (I had to add jest -w='2' --no-cache --coverage |
May be related: #1893 |
@thymikee - it very well could be related. My project is using babel-polyfill. |
This is excellent news, thanks! As an update to our progress in migrating to jest in stylelint:
Using PASS lib/utils/__tests__/isCustomProperty.test.js (40 MB heap size)
PASS lib/rules/selector-no-qualifying-type/__tests__/index.js (44 MB heap size)
PASS lib/rules/selector-max-empty-lines/__tests__/index.js (60 MB heap size)
PASS lib/rules/at-rule-empty-line-before/__tests__/index.js (61 MB heap size) The heapsize then creeps up, until finally the last 4 tests (before it runs out of memory) have heapsizes around 1500mb: PASS lib/utils/__tests__/validateObjectWithStringArrayProps.test.js (1371 MB heap size)
PASS lib/utils/__tests__/isOnlyWhitespace.test.js (1381 MB heap size)
PASS lib/utils/__tests__/findAtRuleContext.test.js (1387 MB heap size)
PASS lib/utils/__tests__/nextNonCommentNode.test.js (1388 MB heap size)
<--- Last few GCs --->
[55400:0x102801600] 214980 ms: Mark-sweep 1397.5 (1525.0) -> 1397.4 (1526.0) MB, 1828.0 / 0.0 ms allocation failure GC in old space requested
[55400:0x102801600] 217100 ms: Mark-sweep 1397.4 (1526.0) -> 1397.2 (1489.0) MB, 2118.8 / 0.0 ms last resort gc
[55400:0x102801600] 218967 ms: Mark-sweep 1397.2 (1489.0) -> 1397.2 (1489.0) MB, 1866.3 / 0.0 ms last resort gc
In the past week we moved away from needing babel, in favour of writing in @cpojer We'll keep poking around at our end as we're keen to move to jest for the excellent developer experience, but we'll keep our fingers crossed that there's a solution within jest for the out-of-memory crashes we're having. |
Wow this is great, thank you so much for the investigation. Here is a bunch more that you should think about:
From the looks of it it seems like one of two things, both equally likely:
One thing I thought could be an issue is code coverage – that definitely requires a ton of memory and at FB we had to bump the memory that node can consume. @DmitriiAbramov did a fantastic job to rewrite code coverage support but to make it really efficient we may need support from the community to make it more "streamy": store coverage on the file system and then process them as a stream at the end of a test run. Alternatively it may also be possible to merge coverage information in the main process after each test has finished running. I don't know how feasible either of them is, though. At FB we currently have one repo with about 5000 test suites and even with coverage we aren't running into any big memory leaks which would hint at a leak issue in your code but I'm not entirely convinced and think it may be a Jest bug. |
It's worth pointing out here that the rule test files, which are causing this memory failure, do not look like standard Jest tests. In order to try switching to Jest without rewriting all of the tests (which would be either a huge manual pain or a moderate jscodeshift pain, would have to try it out), I wrote a setup file that exposes a |
We have the same thing at FB, actually, so I don't think your usage of describe/it is a problem. |
btw. this is where Jest creates workers: https://github.com/facebook/jest/blob/master/packages/jest-cli/src/TestRunner.js#L324 while the slowdown of crashing workers and starting them for each individual test would not be tenable, it is something you can try to change to see if it avoids the memory leak problem (ie. it will ensure it is not a set of tests with leaks but rather the aggregate suite over time) |
I think I have some evidence that the memory problem is likely within Jest, rather than stylelint, because it looks to me like the same problem occurs with very simple tests. I created 200 test files, each with 200 test cases, and each test case nothing more than: describe(`file ${testFileNo}, case ${testCaseNo}`, () => {
it(`file ${testFileNo}, case ${testCaseNo}, spec`, () => {
expect(true).toBe(true)
})
}) Running those tests, I see the same heap growth we saw in stylelint's tests:
|
Hmm ... nevermind. When running those tests I forgot to remove our So that's good news for Jest, suggests that our problem is somewhere in stylelint's own files or it's dependencies. |
That's great progress. Can you share your setup script? Does it do anything with global objects, timers etc. – anything form the environment that it attaches and might stick around and cannot be GC'd? |
Looks like all I need in the setup script to cause the heap to grow is Never debugged a memory leak before. Here we go, I guess ... |
@cpojer: Here's a stylelint update that's partly good, partly not so good ... We found that a nested dependency on However, if we add coverage reporting we still run out of memory — you did mention above that this demands a lot of memory. Jest is kind of "off the hook" for the rule tests, then (:+1:); but the fact remains that Jest demands so much memory that problems arise where they don't with other runners. I wonder if other people experiencing memory problems also have some code somewhere in their app causing a slight memory leak that only becomes a problem when running Jest. |
Yeah you definitely have a special case: massive amounts of tests but low memory. At FB, we have both massive amounts of tests and insane amounts of memory, so it is generally not a problem. I'd love to reduce coverage memory usage and I believe the way to do it is by through either:
Maybe @DmitriiAbramov can help identify how much work that is. This is definitely something where we'll need some help with. |
I don't have experience with workers but have used this method before. Can't make promises around the holiday season, of course, but if you can point me in the direction of some relevant code I'll try to help out with this. |
@cpojer we do merge coverage results after each test. Maybe the easy fix would be to |
@DmitriiAbramov wait we do!? I didn't realize that. We still need to extract coverage data per file for phabricator; if we delete it from individual tests, will we still be able to do this? I think this would dramatically reduce memory usage of Jest. @kentaromiura might be interested as we'd have to change the coverage processor around a bit. |
@cpojer yeah. it should work. testResult.coverage = 'coverage object was removed to reduce memory consumption, run with -keepCoverage' to keep it' or something like that. |
I don't see the value that coverage from one individual test run provides so I'd prefer to just delete it completely after it was merged. imho only the aggregate really matters after a run. If you'd like to know file-specific coverage, run the test in isolation. What do you think? |
i think it doesn't matter in 99%. |
@ooHmartY thanks for the analysis. "Runtime" is what runs each test in a vm context in isolation. This is where it gets tricky: why are these objects retained? It is entirely possible that you are doing something in your tests that causes all your test code to be retained. While I'm not entirely sure if this is a Jest issue, I'd appreciate if you could profile this again with test suites as simple as At Facebook we run thousands of test files in one single run and don't ever run into memory issues like you are describing. I highly doubt that you have a test suite that's bigger than what we have, which hints at this problem being at least partially the user code that is run within Jest. One simple thing I can think of is when you attach listeners or similar to global objects, for example if you did I'm really hoping we can figure out further fixes here. Does my description help? |
Hi @cpojer thanks for the quick reply. Just wanted to clarify that this analysis was run in the actually Jest repo by running the following commands:
The last command was lifted from package.json Looks like there is repo with some simple tests created for #1893 . |
Turned out it's an issue with Here's the relevant issue in JSDOM repo: jsdom/jsdom#1682 Closing this. |
Just FYI we had a very similar issue in the Prettier repo, This commit works around the problem by aliasing |
Ohhhh, this is pretty interesting actually because when you |
This gets more complex when you're testing bundled code (in our case we're using Rollup). Maybe this issue should be documented? |
I have the same issue with the version 22.4.4.
|
As @bertho-zero mentioned, I have implemented the solution from @azz and @cpojer with success!
module.exports = require('fs'); |
This should be fixed in Jest 25.5 btw, via #9443 |
I still have this issue with jest 26.6.3 |
This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. |
This is a specific and concrete problem (I think) related to the performance concerns I voiced in #2171.
There's a recommendation in #1742 and #2162 to use
--runInBand
when running tests on Travis (or, presumably, other slower environments), in order to avoid memory problems that cause slowdowns and failures. When I use--runInBand
on a ton of tests (for stylelint), I do avoid the problems I have without that flag; however, I just end up running into another failure. Apparently Jest consumes all the memory and crashes:The text was updated successfully, but these errors were encountered: