Closing and reverse leakage error in javascript

function(foo, cb) { var bigObject = new BigObject(); doFoo(foo, function(e) { if (e.type === bigObject.type) { cb(); // bigObject = null; } }); } 

The above example shows a classic, random (or maybe not) memory closure. The V8 garbage collector cannot determine if bigObject can be safely removed because it is used in a callback function that can be called multiple times.

One solution is to set bigObject to null when the job in the callback function is complete. But if you use a lot of variables (imagine there are n variables like bigObject and they are all used in the callback), then cleaning up becomes an ugly problem.

My question is this: is there any other way to clear the variables used?

EDIT Here is another example (real world): so I get the application from mongodb and compare it with some other application. The callback from mongodb uses a variable application that is determined from this callback. After receiving the result from mongodb, I return it as a callback as well (because it's all async, and I can't just write return). So it may actually happen that I extend the callback 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) } } 
+18
javascript closures memory-leaks
May 08 '13 at 13:36
source share
2 answers

If your callback function needs to be called once, you should unsubscribe after calling it. This will release your callback + close the GC. With the closure of your closure, bigObject will also be free to collect GC.

This is the best solution - as you noted, the GC does not magically know that your callback will only be called once.

+1
May 08 '13 at 1:40 pm
source share

To build on Brandon's answer: if (for some terrible reason) you cannot refuse to recall your callback, you can always deal with deleting the callback:

 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); }) } 
0
Mar 31 '15 at 16:12
source share



All Articles