假设您有一个组件,其中包括创建一些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实例泄露了内存?
我有点不确定PageFiller实例将在何时收集垃圾(如果它曾经发生过),因为它持有对表示不存在的DOM部分的jquery对象的引用? 或者它与DOM无关,因为根据我的理解,实际的 DOM对象生活在与常规JS变量不同的堆中(除非我在这里弄错了..)
更新:如果主要对象保留对PageFiller的引用,那么事物的变体就是:
Main.prototype.start = function () {
this.filler = new PageFiller();
filler.fillPage();
}
在这种情况下,Main对象具有对PageFiller对象的引用,该对象本身包含对JQ对象的引用;在'remove'之后,JQ对象仍然存在于内存中,但是指向不存在的DOM节点,对吧?
我是否正确地说,在原始示例中,只要main.start()完成:
其他案例:
这次是一个小变化,事件处理程序使问题变得复杂:
PageFiller.prototype.fillPage = function () {
var self = this;
this.dom = ... // as usual
this.dom.click(function () {
alert("Just clicked on dom generated by " + self);
});
}
这一次,只是让PageFiller实例超出范围不足以回收其内存,因为它是由click处理程序中使用的闭包引用的。我在这里泄露了记忆吗?或者我可以信任$(“”)。remove()调用来终止对闭包的引用,从而杀死对PageFiller的最后一个引用?如果我在没有jquery的情况下删除了元素(使用原生DOM API?),那么事情会有什么不同吗?
这可能只是我希望的工作,但我只是想说服自己没有记忆可以从这种模式中泄露出来。
感谢。
答案 0 :(得分:1)
<强>更新强>
删除filler.dom
main.start()
一次完成将减少它所持有的节点的引用计数,因为它不拥有节点(即弱属性)。
当您调用$().remove()
时删除实际节点时,refcount会再次降低为零,并且可以进行垃圾回收。
所以,AFAICT你应该没有什么可担心的。