我看到通过.on()
注册的事件处理程序保存在$.cache
中。
我还看到事件处理程序也保存在$(elem).data()
。
$.cache
中保存的对象是指注册事件的DOM节点。当DOM节点被分离时,这会导致内存泄漏,这会使.off()
调用成为必需的。
我有一种情况,我不知道DOM节点(我附加事件处理程序)何时被分离。虽然我可以在我的代码中保存对该DOM节点的引用并调用.off()
进行清理,但这似乎不太好,因为知道何时删除DOM节点并不是直截了当的。
最好的方法是什么?
答案 0 :(得分:16)
“这样做的最佳方式是什么?”
如果您要使用jQuery,必须使用其API来删除元素,并且您必须使用正确的方法,否则,如您所述,您将有内存泄漏。< / p>
如果您不知道DOM节点何时被删除,以及它是否导致泄漏,我认为这意味着您正在使用另一个库和jQuery。出于这个原因,这不是一个好主意。
您需要确保jQuery删除受jQuery影响的任何元素。您还没有明确设置$.cache
中存储的一些数据。这意味着应该使用jQuery删除所有元素,而不仅仅是那些认为可能包含数据的元素。
“jQuery中
$.cache
的目的是什么?”
将处理程序和其他数据与元素相关联。数据和元素之间的链接基本上是存储在元素上的expando属性上的序列号。
如果删除没有jQuery的元素,$.cache
中的关联数据将成为孤立数据。
这种方法的目的是防止潜在的泄漏。不幸的是,它可能会造成更严重的泄漏。
答案 1 :(得分:6)
我遇到了类似的情况,其中Knockout用于添加和删除文档中的dom树。但是,jquery用于将事件侦听器附加到这些dom树。当knockout从文档中删除dom元素时,侦听器不会被解除绑定,因此dom树永远不会有资格进行垃圾回收。我们添加了一个清理函数,每次哈希更改时都会遍历jquery $ .cache,并找到绑定到文档中不存在的dom树的处理程序。然后它取消绑定听众,从而使得dom树有资格进行垃圾收集并修复我们看到的大部分泄漏,即用于泄漏13MB的应用程序往返,现在它在这些更改时仅泄漏3MB。
for (var i in $.cache) {
if ($.cache.hasOwnProperty(i)) {
if ($.cache[i].handle && $.cache[i].handle.elem && document !== $.cache[i].handle.elem && !jQuery.contains(document, $.cache[i].handle.elem)) {
//we have an event handler pointing to a detached dom element!
//this is a memory leak as this detached dom element cannot be garbage collected until
//all references to it are removed. So lets delete the event handler to get memory back!
var orphan = $($.cache[i].handle.elem);
$('body').append(orphan);
orphan.off();
orphan.remove();
orphan = null;
}
}
}