Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Avoid memory leak with objects that create and remove DOM with jquery

Suppose you have a component whose job is, among other things, to create some DOM node (eg with jquery) :

function PageFiller() {
}
PageFiller.prototype.fillPage = function () {
  this.dom = $("<div/>", {
    "class" : "hello",
    text : "Hello world"
  });
  $("body").append(this.dom);
}

Suppose that another component uses this to fill the DOM, without keeping a reference to the "PageFiller"

function Main() {
}
Main.prototype.start = function () {
   var filler = new PageFiller();
   filler.fillPage();
};
var main = new Main()
main.start();

No suppose that right after that (in the same scope), someone brutally clears the DOM :

$(".hello").remove();

What is the memory layout in such a situation ? Have I leaked memory with the PageFiller instance ?

I'm a bit unsure at which point the PageFiller instance would get garbage collected (if it ever happen), since it holds a reference to a jquery object representing part of the DOM that does not exists anymore ? Or does it have nothing to do with the DOM, since from what I understand the actual DOM objects live in a different heap than the regular JS variables (unless I am mistaken here..)

UPDATE : A variation of the thing would be if the reference to the PageFiller was kept by the Main object :

Main.prototype.start = function () {
    this.filler = new PageFiller();
    filler.fillPage();
}

In this situation, the Main object has a reference to the PageFiller object, which itself holds a reference to a JQ object ; after the 'remove', the JQ object still exists in memory, but points to non-existent DOM nodes, right ?

Am I correct to say that in the original example, as soon as main.start() is finished :

  • no object holds a reference to the PageFiller object, so it gets garbage collected, and the pageFiller.dom object is not referenced by anyone, so it gets garbage collected too ?
  • the actual DOM elements obviously still exists in memory, but in a separate heap that I don't really have to worry about

OTHER CASE :

This time a small variation, with event handlers to complicate matters :

PageFiller.prototype.fillPage = function () {
  var self = this;
  this.dom = ... // as usual 
  this.dom.click(function () {
    alert("Just clicked on dom generated by " + self);
  });
}

This time, just letting the PageFiller instance run out of scope could not be enough to have its memory reclaimed, since it is referenced by the closure used in the click handler. Have I leaked memory here ? Or can I trust the $("").remove() call to kill the reference to the closure, hence killing the last reference to the PageFiller ? And would things behave differently if I removed the element without jquery (with the native DOM API ?)

This probably all just work as I hope, but I'm just trying to convince myself that no memory can leak from this pattern.

Thanks.

like image 847
phtrivier Avatar asked Nov 13 '22 04:11

phtrivier


1 Answers

Updated

Removing the filler.dom once main.start() has finished will decrease the refcount for the nodes it's holding on to, because it doesn't own the nodes (i.e. weak property).

When the actual nodes are being removed when you call $().remove() the refcount again gets decreased to zero and can be garbage collected.

So, AFAICT you should have nothing to worry about.

like image 96
Ja͢ck Avatar answered Nov 16 '22 03:11

Ja͢ck