-
-
Notifications
You must be signed in to change notification settings - Fork 3.9k
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
JavaScript heap out of memory on version 5.10.0 and above #9864
Comments
It'll be difficult for us to try to repro this without a data dump. But one way you can work around this is to reduce the cursor's return Answer.find({}).batchSize(10).sort(...).populate(...).cursor(); That will reduce the memory usage |
Thanks. But the issue is not the code itself, it is that the exact same codebase works (i.e. does not throw an Out of Memory error) with versions up to 5.9.29 but not on 5.10.x I assume that something might have changed on how embedded documents are handled (i.e. population of those) or it is an issue with the updated driver (i.e. Unfortunately the only help I can provide is pinpointing the issue to changes between these exact 2 versions. |
Can you confirm whether reducing the One possibility is that this is caused by #8380 |
I encountered a potentially similar issue:
|
@vkarpov15 I tried with the latest mongoose version i.e. 5.11.15 using
At the moment we have reverted back to 5.9.29 in production where this and other similar report scripts work flawlessly. |
@xeroxoid how are you iterating through the cursor? async iterator, @rsnr can you please provide more info on what |
@vkarpov15 we i.e.
Please note that |
Hi @vkarpov15 , the // do something section iterates the mongoose query results and adds some of them to global objects. UPDATE: |
Issue identified on version 5.11.19, query is as following
reproduced also while using eachAsync Edit:We needed to revert back to version |
@o-b-one : aligned with my issue: works fine at mongoose 5.7.14, and fails on heap out of memory as of mongoose 5.8.0 and onward. |
I did some digging and found that this is an issue with the fix for #8092. Line 4466 in 337e3b9
Below is the script I used to repro this: 'use strict';
const mongoose = require('mongoose');
mongoose.set('useFindAndModify', false);
const { Schema } = mongoose;
run().catch(err => console.log(err));
async function run() {
await mongoose.connect('mongodb://localhost:27017/test', {
useNewUrlParser: true,
useUnifiedTopology: true
});
const Answer = mongoose.model('Answer', Schema({
choice: String,
question: { type: 'ObjectId', ref: 'Question' }
}));
const Question = mongoose.model('Question', Schema({
text: String
}));
const numQs = await Question.countDocuments();
if (numQs < 10000) {
await Question.deleteMany();
await Answer.deleteMany();
for (let i = 0; i < 100000; ++i) {
const q = await Question.create({ text: 'my question' });
const answers = [];
for (let j = 0; j < 10; ++j) {
answers.push({ choice: 'B', question: q });
}
await Answer.create(answers);
if (i % 100 === 0) console.log(i);
}
}
let i = 0;
await Answer.find().populate('question').cursor().eachAsync((doc) => {
if (i++ % 100 === 0) {
console.log('Iterated', i);
}
});
console.log('Done');
} Sorry for the trouble, the fix will be in v5.12.5 👍 |
let count = 0;
MyModel.find({}, 'field1 field2 field3').sort({timestamp: -1}).lean().cursor().eachAsync(doc => { ++count; ... }).then(() => {
console.log('Done');
}); |
@rsnr I managed to confirm there's an issue where the below script succeeds on Mongoose 5.7.14, but crashes with OOM after about 31k documents in Mongoose 5.8.0 'use strict';
const async = require('async');
const mongoose = require('mongoose');
mongoose.set('useFindAndModify', false);
const { Schema } = mongoose;
run().catch(err => console.log(err));
async function run() {
await mongoose.connect('mongodb://localhost:27017/test', {
useNewUrlParser: true,
useUnifiedTopology: true,
});
const Answer = mongoose.model('Answer', Schema({
choice: String,
question: { type: 'ObjectId', ref: 'Question', index: true }
}, { timestamps: true }));
const Question = mongoose.model('Question', Schema({
text: String
}));
const numQs = await Question.countDocuments();
if (numQs < 10000) {
await Question.deleteMany();
await Answer.deleteMany();
for (let i = 0; i < 100000; ++i) {
const q = await Question.create({ text: 'my question' });
const answers = [];
for (let j = 0; j < 10; ++j) {
answers.push({ choice: 'B'.repeat(1000), question: q });
}
await Answer.create(answers);
if (i % 100 === 0) console.log(i);
}
}
const numDocs = await Answer.countDocuments();
let position = 0;
let roundSize = 1000;
async.whilst(
function() { return position < numDocs; }, // async v2.x format
function iter(callback) {
Answer.find({}, 'choice question').sort({createdAt: -1})
.skip(position).limit(roundSize).lean().exec(function(err, allFound) {
if (err) { console.log(err) }
else {
/// do something
}
console.log('Iterated', position);
callback(null, position);
});
position += roundSize;
},
function (err, n) {
console.log('Done', err, n);
}
);
} This issue seems to only affect callbacks. You can work around this memory leak by using promises instead as shown below. async.whilst(
function() { return position < numDocs; }, // async v2.x format
function iter(callback) {
Answer.find({}, 'choice question').sort({createdAt: -1})
.skip(position).limit(roundSize).lean().then(function(allFound) {
//if (err) { console.log(err) }
//else {
/// do something
//}
console.log('Iterated', position);
callback(null, position);
}).catch(err => console.log(err));
position += roundSize;
},
function (err, n) {
console.log('Done', err, n);
}
); It looks like it is caused by the changes in #8259, will keep digging and see what I can find 👍 |
It has something to do with clearing timeouts. Wrapping |
Thanks so much @vkarpov15 for researching this issue and suggesting these two alternative code changes. |
Do you want to request a feature or report a bug?
bug
What is the current behavior?
On operations that use a cursor, after some time the following error occurs:
FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory
If the current behavior is a bug, please provide the steps to reproduce.
As seen on the snippet above many document properties have to be populated (this is used to generate a specific report).
After some time the error noted above is generated and the process quits.
What is the expected behavior?
The process should complete.
The thing is that with any version below 5.10.0, i.e. 5.9.29 (which we have reverted to) the same code works fine.
I would guess it has to do with the "upgrade to MongoDB driver 3.6 for full MongoDB 4.4 support", but have no proof on that.
What are the versions of Node.js, Mongoose and MongoDB you are using? Note that "latest" is not a version.
NodeJS: v14.15.4
Mongoose: 5.10.x (any version starting at 5.10.x)
MongoDB: v4.2.9
The text was updated successfully, but these errors were encountered: