避免使用 jquery 创建和删除 DOM 的对象发生内存泄漏

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

本文关键字:对象 泄漏 内存 DOM 删除 jquery 创建      更新时间:2023-09-26

假设你有一个组件,其工作之一是创建一些DOM节点(例如使用jquery):

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

假设另一个组件使用它来填充 DOM,而不保留对"PageFiller"的引用

function Main() {
}
Main.prototype.start = function () {
   var filler = new PageFiller();
   filler.fillPage();
};
var main = new Main()
main.start();
不假设在那

之后(在同一范围内),有人残酷地清除了 DOM:

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

在这种情况下的内存布局是什么?我是否泄漏了页面填充实例的内存?

我有点不确定PageFiller实例会在什么时候被垃圾回收(如果它发生的话),因为它包含一个对jquery对象的引用,该对象表示不再存在的DOM的一部分?或者它与 DOM 无关,因为据我了解,实际的 DOM 对象与常规 JS 变量位于不同的堆中(除非我在这里弄错了......

更新:事情的一个变体是,如果对PageFiller的引用由主要对象保留:

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

在这种情况下,Main 对象具有对 PageFiller 对象的引用,该对象本身包含对 JQ 对象的引用;在"删除"之后,JQ 对象仍然存在于内存中,但指向不存在的 DOM 节点,对吗?

我是否正确地说,在原始示例中,一旦 main.start() 完成:

  • 没有对象包含对PageFiller对象的引用,因此它被垃圾回收,并且pageFiller.dom对象没有被任何人引用,所以它也会被垃圾回收?
  • 实际的 DOM 元素显然仍然存在于内存中,但在我真的不必担心的单独堆中

其他情况 :

这次有一个很小的变化,事件处理程序使事情复杂化:

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

这一次,仅仅让 PageFiller 实例超出范围不足以回收其内存,因为它是由单击处理程序中使用的闭包引用的。我在这里泄露了记忆吗?或者我可以信任 $(").remove() 调用来终止对闭包的引用,从而杀死对 PageFiller 的最后一个引用?如果我在没有 jquery 的情况下删除元素(使用本机 DOM API?

这可能一切都像我希望的那样工作,但我只是想说服自己,没有记忆可以从这种模式中泄漏。

谢谢。

已更新

main.start()完成后删除filler.dom将减少它所持有的节点的引用计数,因为它不拥有节点(即弱属性)。

当您调用$().remove()时删除实际节点时,引用计数再次减少到零,并且可以进行垃圾回收。

所以,AFAICT你应该没有什么可担心的。