stryker-js: Potential Memory Leak
Summary
Allocation failed - JavaScript heap out of memory
during mutation testing on moderately-sized project module. I’ve tried increasing heap space to 8GB, but it still ultimately OOMs.
Stryker config
module.exports = function(config) {
config.set({
testRunner: "mocha",
mutator: "javascript",
transpilers: [],
reporter: ["clear-text", "progress"],
testFramework: "mocha",
coverageAnalysis: "perTest",
mutate: ["src/**/!(*.spec).js"],
mochaOptions: {
files: ["index.js", "test/dependencies.js", "src/**/*.spec.js"],
},
});
};
Stryker environment
├─┬ stryker@0.24.1
├─┬ stryker-api@0.17.2
├─┬ stryker-html-reporter@0.14.2
├─┬ stryker-javascript-mutator@0.7.2
├─┬ stryker-mocha-framework@0.10.2
├─┬ stryker-mocha-runner@0.12.2
Your Environment
software | version(s) |
---|---|
node | v9.9.0 |
npm | 6.0.0 |
Operating System | MacOS 10.12.6 |
Stack Trace
[2018-06-28 14:01:23.999] [INFO] Stryker - 86764 Mutant(s) generated
[2018-06-28 14:01:25.129] [INFO] SandboxPool - Creating 4 test runners (based on CPU count)
<--- Last few GCs --->
[97626:0x103800000] 126169 ms: Mark-sweep 8184.6 (8216.9) -> 8184.6 (8216.9) MB, 88.1 / 0.0 ms allocation failure GC in old space requested
[97626:0x103800000] 126261 ms: Mark-sweep 8184.6 (8216.9) -> 8184.6 (8215.9) MB, 92.0 / 0.0 ms last resort GC in old space requested
[97626:0x103800000] 126423 ms: Mark-sweep 8184.6 (8215.9) -> 8184.6 (8215.9) MB, 162.1 / 0.0 ms last resort GC in old space requested
<--- JS stacktrace --->
==== JS stack trace =========================================
Security context: 0x1c8f1b025529 <JSObject>
1: fromString(aka fromString) [buffer.js:336] [bytecode=0x1c8fa68fb241 offset=161](this=0x1c8fddf822d1 <undefined>,string=0x1c8f12923071 <Very long string[3403188]>,encoding=0x1c8f1b036441 <String[4]: utf8>)
2: nextMutant(aka nextMutant) [/Users/jacobbiggs/repos/akitabox/packages/server-modules/node_modules/stryker/src/transpiler/MutantTranspiler.js:~36] [pc=0x3717e3bfad5f](this=0x1c8fdd...
FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory
1: node::Abort() [/usr/local/bin/node]
2: node::FatalTryCatch::~FatalTryCatch() [/usr/local/bin/node]
3: v8::internal::V8::FatalProcessOutOfMemory(char const*, bool) [/usr/local/bin/node]
4: v8::internal::Factory::NewRawOneByteString(int, v8::internal::PretenureFlag) [/usr/local/bin/node]
5: v8::internal::String::SlowFlatten(v8::internal::Handle<v8::internal::ConsString>, v8::internal::PretenureFlag) [/usr/local/bin/node]
6: v8::String::WriteUtf8(char*, int, int*, int) const [/usr/local/bin/node]
7: node::StringBytes::Write(v8::Isolate*, char*, unsigned long, v8::Local<v8::Value>, node::encoding, int*) [/usr/local/bin/node]
8: node::Buffer::New(v8::Isolate*, v8::Local<v8::String>, node::encoding) [/usr/local/bin/node]
9: node::Buffer::(anonymous namespace)::CreateFromString(v8::FunctionCallbackInfo<v8::Value> const&) [/usr/local/bin/node]
10: v8::internal::FunctionCallbackArguments::Call(void (*)(v8::FunctionCallbackInfo<v8::Value> const&)) [/usr/local/bin/node]
11: v8::internal::MaybeHandle<v8::internal::Object> v8::internal::(anonymous namespace)::HandleApiCallHelper<false>(v8::internal::Isolate*, v8::internal::Handle<v8::internal::HeapObject>, v8::internal::Handle<v8::internal::HeapObject>, v8::internal::Handle<v8::internal::FunctionTemplateInfo>, v8::internal::Handle<v8::internal::Object>, v8::internal::BuiltinArguments) [/usr/local/bin/node]
12: v8::internal::Builtin_Impl_HandleApiCall(v8::internal::BuiltinArguments, v8::internal::Isolate*) [/usr/local/bin/node]
13: 0x3717e37842fd
Abort trap: 6
About this issue
- Original URL
- State: closed
- Created 6 years ago
- Reactions: 2
- Comments: 32 (26 by maintainers)
Commits related to this issue
- feat(mutants): Prevent memory leak when transpiling mutants Instead of transpiling all mutants at once, this PR makes it so that at most 100 mutants are transpiled at any one time. After that, it wai... — committed to stryker-mutator/stryker-js by nicojs 5 years ago
- fix(mutants): Prevent memory leak when transpiling mutants (#1376) Instead of transpiling all mutants at once, this PR makes it so that at most 100 mutants are transpiled at any one time. After tha... — committed to stryker-mutator/stryker-js by nicojs 5 years ago
Oh, congrats on the 1.0 @nicojs & team!
I no longer have access to the repository that demonstrated issues here… but @ian-craig might be interested… 😉
This issue should be fixed with #1376. We’ll be releasing a version later today. I’ll notify here when it is released
This is for performance reasons. We reuse the test runner process. With mocha, we clear only your modules from the node cache so Sinon will still be in de cache and happely clog your memory.
For jest, we leave the clearing up to the jest testrunner. Not sure what exactly is cleared there, but I imagine it’s the same thing
Ah, this is slightly different from the original error, as this happens in a test runner child process.
Stryker should be able to recover from that. We could identify this error and retry to run mutant in a fresh Testrunner process. In fact, there already is a decorator to do just that, but it isn’t handeling this particular case: the
RetryDecorator
. I think we should do that, as well as investigate the jest runner