function(foo, cb) {
var bigObject = new BigObject();
doFoo(foo, function(e) {
if (e.type === bigObject.type) {
cb();
// bigObject = null;
}
});
}
In this example above we see classic accidentally (or maybe not) creation of a closure which can be responsible for memory leaks. The V8 garbage collector can't know if it is safe to remove bigObject because it is used in the callback function which can be called several times.
One solution is to set bigObject to null when the job in the callback function is over.
But if you are using many variables (imagine there is n variables like bigObject and there are all used in callback) then cleaning this becomes an ugly problem.
My question is: is there any other way for cleaning used variables?
EDIT : some another (real world example) : So i get application from mongodb and compare it to some other application. Callback from mongodb uses variable application that is defined out of that callback. After I get result from mongodb I return it also as a callback (because it is all async and I cant just write return ). So actually it can happen that i propagate callback all the way to the source...
function compareApplications(application, condition, callback) {
var model = database.getModel('Application');
model.find(condition, function (err, applicationFromMongo) {
var result = (applicationFromMongo.applicationID == application.applicationID)
callback(result)
}
}
If your callback function is only supposed to be called once, then you should unsubscribe after it is called. That will release your callback + closure to the GC. With your closure released, bigObject will also be free to be collected by the GC.
That's the best solution - as you noted, the GC doesn't magically know your callback will only be called once.
To build on Brandon's answer: If (for some terrible reason) you are unable to unsubscribe your callback you could always handle deleting the callback yourself:
function createSingleUseCallback(callback)
{
function callbackWrapper()
{
var ret = callback.apply(this, arguments);
delete callback;
return ret;
}
return callbackWrapper;
}
function compareApplications(application, condition, callback)
{
var model = database.getModel('Application');
model.find(condition, createSingleUseCallback(function (err, applicationFromMongo)
{
var result = (applicationFromMongo.applicationID == application.applicationID);
callback(result);
})
}