-
-
Notifications
You must be signed in to change notification settings - Fork 3k
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
Declarations do not get cleaned up unless you set them to null
#1991
Comments
how do we know we're not just waiting on the garbage collector? |
Shouldn't gc run after each test? |
I have also experienced this. Mocha is storing the callbacks and it won't clean up because the runtime doesn't know if you will call those "callbacks" or not. And the memory footprint can be really substantial if your test suite is large. So I agree that it should clean up after each test. |
feel free to try and fix this; I'm probably going to be heads-down on a rewrite for awhile. |
Anyone know a solution to prevent this other than manually cleaning up after each test? I created a related issue here #2030 thanks! |
Nope, just like your node server won't run gc between each request. Here's an example: // node --trace-gc --max-old-space-size=10 testing.js
var fn;
var obj;
var i = 0;
setInterval(function() {
fn = function() {
// Create some objects
obj = [];
for (var j = 0; j < 100; j++) {
obj.push(j * j);
}
if (++i % 1000 === 0) {
console.log(i);
}
};
fn();
}, 1); You'll likely only see Scavenge (which collects objects in new space) get invoked every 1000 invocations of fn, which includes 1000 allocations of those medium sized arrays, as well as a new fn being assigned to the outer scope. You probably shouldn't see the MarkSweep collector during that test. If interested, here's some more info: http://jayconrod.com/posts/55/a-tour-of-v8-garbage-collection
If a single test invokes the "done" callback once at the start of the suite, and a second time right before the test suite ends, wouldn't you want to know about this error? You can only do that by keeping reference to old test objects, though we could certainly delete the functions from test runnables (not hooks) after they've been ran. Might help a bit. |
@rodoabad I think your test is too small. If you increased the number of iterations, you should start seeing GC kick in. |
Hello. I can confirm I've encountered this as well. I've upgraded @rodoabad reproduction to:
The cause is that mocha keeps references to test functions (it/before/after/...) to allow The hack workaround is to manually cleanup mocha references on "suite end" event. runner.on('suite end', function (suite) {
delete suite.tests;
delete suite._beforeAll;
delete suite._beforeEach;
delete suite._afterEach;
delete suite.ctx;
delete suite._afterAll;
}); this cleans up too much and probably needs to be more precise...
Taking a heap snapshot forces garbage collection beforehand
<
Try The workaround above. does it solve your problem? |
@bd82 thank you very much for the comment! I tried your suggestion, however I didn't see much difference (unless I'm doing it wrong). Since I'm using karma-mocha I had to stick my Some profiling results: |
@gumatias Thanks for trying the hack. Some thoughts:
we also use karma-mocha in the production code that suffered from these issues. Additionally we use require.js so we have a test-main.js file that configures require.js and starts the tests. in test-main.js var orgMochaRun = mocha.run;
mocha.run = function(fn) {
var runner = orgMochaRun(fn);
runner.on('suite end', function(suite) {
delete suite.tests;
delete suite._beforeAll;
delete suite._beforeEach;
delete suite._afterEach;
delete suite.ctx;
delete suite._afterAll;
});
}; |
Our tests are also split into multiple executions. However, splitting our tests into even smaller parts will just keep hiding the root cause of the problem. Thanks! |
I've suggested a pull request. |
@gumatias I'm not sure your problem is that exactly the one I am trying to solve in the pull request. If you do try it, you should take a heap snapshot and compare heap size.
comparing before / after proves you have a memory leak, but does not show the effects if you can upload one of your spec files I can have a look and see if you are using global |
(it/before[Each]/after[Each]). related to mochajs#1991.
FWIW @rodoabad @danielstjules It appears that PhantomJS runs garbage collection only on page close |
There would seem to be more to the story than just page close GC. If GC wasn't run at all until page close, I would think that nulling local vars would have no impact, unless there are separate types/phases of GC where nulling a local var immediately triggers GC. I'm more inclined to believe this has to do function references being held onto. |
I am a bot that watches issues for inactivity. |
Apologies for necromancy, but this issue is still open and I do not think it is a problem anymore. See rodoabad/mocha-memory-leak#1 - I was not able to reproduce this issue using the latest version of mocha. I've asked @rodoabad to take a peek and consider closing this issue if he agrees. |
@jjoekoullas thanks. |
@boneskull @jjoekoullas I'll be closing this issue now. To everyone else, if you think this is still an issue, feel free to reference this issue. |
@boneskull Just wondering if we should be actively cleaning up out declarations per describe block.
Leaking
Not Leaking
More here - https://github.com/rodoabad/mocha-memory-leak
The text was updated successfully, but these errors were encountered: