Hof*_*ann 23 javascript jquery events garbage-collection
我的应用程序中没有遇到内存泄漏,但我担心将来可能出现问题.我想知道是否做这样的事情:
SomeClass.prototype.someMethod= function() {
var that= this
this.$div2.click(function() {
that.someMethod2();
});
}
Run Code Online (Sandbox Code Playgroud)
让我们说这个.$ div2附加到另一个div.$ div1.如果我打电话
this.$div1.remove();
Run Code Online (Sandbox Code Playgroud)
然后失去了我的SomeClass实例的引用,SomeClass实例是否被垃圾收集?那个HTML元素呢.$ div2?这个.$ div2不会在DOM里面,因为它被附加到这个.$ div1.
我问这个是因为.$ div2中的事件处理程序可能会保留对HTML元素的引用.$ div2并且由于变量"that"而通过闭包保留对SomeClass实例的引用.
那么我应该关心如何正确删除所有事件和这样的HTML元素?或者只是删除"root"元素(这个.$ div1)解决了这个问题?
Ber*_*rgi 17
this.$div2附加到this.$div1.如果我调用this.$div1.remove();后来丢失了我的SomeClass实例的引用,那么实例是否SomeClass会收集垃圾?
是的,当所有对它的引用都丢失时 - 也就是那些通过事件处理程序的引用 - 实例可以被垃圾收集.
那个HTML元素
this.$div2呢?this.$div2不会在DOM中,因为它被附加到this.$div1.
它是否当前附加到DOM并不重要.如果某些不可收集的对象引用$div1,它也可以访问其子节点$div2和那个事件处理程序,因此从处理程序引用的实例将不可收集.
我问这个是因为事件处理程序
this.$div2可能会保留对HTML元素this.$div2的引用,并且SomeClass由于变量"that" 而保持对闭包实例的引用.
这是一个循环引用,并且应该由引擎很好地处理(当圈内的任何对象都没有从外部引用时,它可以被收集).但是,(旧的?)Internet探索者在圈子中涉及DOM对象时无法执行此操作.
出于这个原因,.removejQuery方法(代码)在内部调用(内部)cleanData方法,该方法分离所有事件侦听器.
那么我应该关心如何正确删除所有事件和这样的HTML元素?或者只是删除"root"元素(这个.$ div1)解决了这个问题?
是的,调用removejQuery包装器会自动删除所有事件(来自所有子元素)和DOM节点.
我应该关心如何正确删除所有事件和这样的HTML元素吗?
最简洁的答案是不!至少在99%的情况下,以任何方式都无关紧要,因为与网页使用的整体内存相比,一个DOM元素使用的内存是微不足道的.
但是,释放通过处置不需要的对象所使用的内存总是一个好习惯,但是你不能说GC肯定会释放元素使用的内存,因为垃圾收集完全取决于浏览器!理论上GC只应该在没有DOM元素引用的情况下启动,至少Chrome的工作方式是这样,但是在像JavaScript这样的语言中,你没有明确告诉你完成对象的运行时间,事情就是如此迅速地在JavaScript中乱码:一个函数可能会将对象传递给更多的函数,对象可能会作为另一个对象中的成员被保存掉,一个对象可能会通过闭包等引用,所以它完全取决于浏览器如何什么收集!
在你的情况下删除div1释放html文档并且元素不会在视图中呈现,实际上jQuery的remove方法负责删除与元素本身一起附加到元素的所有事件,expando属性和子元素,但是你保留了参考div1和div2在另一个对象中制作两个DOM元素的孤儿元素!删除 SomeClass实例变量会释放对DOM元素的所有引用,使它们成为垃圾收集的候选者,但是这里有一个棘手的that变量,它导致DOM元素引用了SomeClass通过clusure 的实例!此问题Circular Reference在IE中称为:
存储彼此引用的JavaScript对象和DOM元素导致Internet Explorer的垃圾收集器无法回收内存,从而导致内存泄漏

这个特定的泄漏主要是IE <8的历史兴趣,但打破循环链接的一个很好的例子是避免使用变量that,而是使用代理或委托将事件处理程序的上下文更改为某个特定的上下文.
当涉及DOM事件处理程序时,ECMA 5th绑定方法退出有用的更改上下文,这里是一个基于代码的简单处理程序,而不使用变量闭包:
this.$div2.click((function() {
this.someMethod2();
}).bind(this));
Run Code Online (Sandbox Code Playgroud)