Javascript closure: memory leak

I have a memory leak, I do not understand. I programmed a semi-automatic decoupling event processing mechanism that should allow me to easily clear my memory. But in one case, the cleaning does not happen (I use the chrome profile (heap of memory) "to check that the instances of" EventHandler "are left). I really don’t understand why this is happening. There is something strange with closing ...

see in action with chrome

function Bind(obj, f) { return function() { return f.apply(obj, arguments); } } function EventHandler() { this.listeners = new Object(); var _listenerID = 0; this.addListener = function(e, obj, listener, specialDisplay) { if (typeof(listener) === "function") { var listenerID = ++_listenerID; console.log("Events (" + (++EventHandler.All) + ", " + listenerID + ") ++" + e); if (!this.listeners.hasOwnProperty(e)) { this.listeners[e] = new Object(); } this.listeners[e][listenerID] = listener; if (obj != null && typeof(obj.removeListener) == "function") { var deleteListenerID = obj.addListener("Delete", null, Bind(this, function() { this.removeListener(e, listenerID); obj.removeListener("Delete", deleteListenerID); })); } return listenerID; } return null; } this.fire = function(e, obj) { if (this.listeners.hasOwnProperty(e)) { for(var i in this.listeners[e]) { this.listeners[e][i](obj); } } } this.removeListener = function(e, listenerID) { if (this.listeners.hasOwnProperty(e) && this.listeners[e].hasOwnProperty(listenerID)) { delete this.listeners[e][listenerID]; console.log("Events (" + (--EventHandler.All) + ", " + listenerID + ") --" + e); } } } EventHandler.All = 0; function Loader() { } Loader.files = new Object(); Loader.LoadImage = function(src, f) { if (!Loader.files.hasOwnProperty(src)) { var handler = new EventHandler(); console.log("Loading.... (" + src + ")"); Loader.files[src] = function(fnct) { handler.addListener("ImageLoaded", handler, function(img) { fnct(img); }); } handler.addListener("ImageLoaded", handler, function() { Loader.files[src] = function(fnct) { fnct(img); } }); var img = new Image(); $(img).load(function() { console.log("Loaded.... (" + src + ")"); handler.fire("ImageLoaded", img); handler.fire("Delete"); $(img).unbind('load'); }); img.src = src; } Loader.files[src](f); } Loader.LoadImage("http://serge.snakeman.be/Demo/house.jpg", function() { alert("ok"); }); 
+6
source share
2 answers

Closures are created that contain a reference to the EventHandler instance via the handler variable. One of the closures remains after loading the image:

  handler.addListener("ImageLoaded", handler, function() { Loader.files[src] = function(fnct) { fnct(img); } }); 

This is an internal function function(fnct) {... An EventHandler instance cannot be released as long as a close exists. Your only decision is to get rid of this closure. Or, if possible, you are producing the instance manually. For you, the following may be done:

 handler.fire("Delete"); handler = undefined; 

The Chrome memory profiler shows you the object's save tree, which is another way of saying "Who holds the link to this object." In your example, this is an EventHandler <- handler (a variable of the LoadImage method that is enabled by closing) <- house.jpg which is actually equal to Loader.files[src] and has the value function(fnct) { fnct(img); } function(fnct) { fnct(img); } .

+2
source

While you are adding β€œlisteners”, make sure you delete it if you use the query for a long time.

 this.listeners = new Object(); 

or

 this.listeners[e] = new Object(); 

this will add the object to the listener as an array, but will not delete it at any time.

This may cause memory consumption. It cannot flow, its purpose is objects. which consumes your RAM using a browser. :)

+2
source

All Articles