I am building a game with a requestAnimationFrame
loop that includes a call to jQuery html()
method. It just updates the text in a status window next to the game action.
我正在构建一个带有requestAnimationFrame循环的游戏,该循环包括对jQuery html()方法的调用。它只是更新游戏操作旁边的状态窗口中的文本。
I notice with Chrome's timeline monitor, that the DOM nodes go up and up and up, thousands in a minute! And when I change my code from:
我注意到Chrome的时间线监视器,DOM节点上升和上升,每分钟数千!当我改变我的代码:
// creates a ton of DOM nodes
$("#readout").html(data);
to
// DOM nodes does not increase over time
document.getElementById('readout').innerHTML = data;
the 'memory leak' goes away.
“记忆泄漏”消失了。
2 个解决方案
#1
7
Short answer: No.
简答:没有。
Long answer: You likely have something else going on in your page/code.
答案很长:您的页面/代码中可能还有其他内容。
A memory leak is generally caused by a circular reference between the Javascript engine and the DOM. For example:
内存泄漏通常是由Javascript引擎和DOM之间的循环引用引起的。例如:
var div = document.getElementById('divId');
div.onclick = function() {
doSomething(div);
};
The script obtains a reference to a div on the page. So far we're fine. The next line assigns a function to an event handler on the DOM, creating a reference from the DOM to the Javascript engine - half way to a leak. The function body uses the tag, which creates a Closure - the tag reference is kept with the function for future calls to it. That completes the circular reference between the tag -> function (DOM -> JS) and function -> tag (JS -> DOM), and so the 2 will sit in memory until the browser's process is destroyed.
该脚本获取对页面上div的引用。到目前为止,我们没事。下一行将一个函数分配给DOM上的事件处理程序,创建从DOM到Javascript引擎的引用 - 泄漏的一半。函数体使用标签创建一个Closure--标签引用与函数一起保存,以便将来调用它。这完成了标记 - >函数(DOM - > JS)和函数 - >标记(JS - > DOM)之间的循环引用,因此2将位于内存中,直到浏览器的进程被销毁。
So in order for either line of code you mentioned to leak, it would have to be eliminating tags that had events attached like above (or data that follows a similar pattern). But, jQuery's .html(string) goes out of its way to prevent these:
因此,为了使您提到的任何一行代码泄漏,它必须消除具有上述事件附加的标记(或遵循类似模式的数据)。但是,jQuery的.html(字符串)不遗余力地阻止这些:
// Remove element nodes and prevent memory leaks
elem = this[i] || {};
if ( elem.nodeType === 1 ) {
jQuery.cleanData( getAll( elem, false ) );
elem.innerHTML = value;
}
So it's looping through all the tags inside the tag you're running .html(string) on and running cleanData() on them, which in turn does this:
所以它循环遍历标签内的所有标签,你正在运行.html(字符串)并在它们上运行cleanData(),这反过来做到这一点:
jQuery.removeEvent( elem, type, data.handle );
Thus preventing the leak.
从而防止泄漏。
So in order to leak memory with this method and not the browser built-in .innerHTML you'd have to be triggering some very obscure browser bug (seems pretty unlikely), or more likely something else is going on and you're mistaking it for jQuery's .html(string).
所以为了使用这种方法泄漏内存而不是浏览器内置的.innerHTML,你必须触发一些非常模糊的浏览器错误(似乎不太可能),或者更可能是其他东西正在发生而你却误以为对于jQuery的.html(字符串)。
#2
2
Always use .empty().html(...)
instead of just .html()
始终使用.empty()。html(...)而不仅仅是.html()
.empty()
unbinds the event listeners from the DOM objects you are about to remove, and removes them gracefully.
.empty()从您要删除的DOM对象中取消绑定事件侦听器,并正常删除它们。
#1
7
Short answer: No.
简答:没有。
Long answer: You likely have something else going on in your page/code.
答案很长:您的页面/代码中可能还有其他内容。
A memory leak is generally caused by a circular reference between the Javascript engine and the DOM. For example:
内存泄漏通常是由Javascript引擎和DOM之间的循环引用引起的。例如:
var div = document.getElementById('divId');
div.onclick = function() {
doSomething(div);
};
The script obtains a reference to a div on the page. So far we're fine. The next line assigns a function to an event handler on the DOM, creating a reference from the DOM to the Javascript engine - half way to a leak. The function body uses the tag, which creates a Closure - the tag reference is kept with the function for future calls to it. That completes the circular reference between the tag -> function (DOM -> JS) and function -> tag (JS -> DOM), and so the 2 will sit in memory until the browser's process is destroyed.
该脚本获取对页面上div的引用。到目前为止,我们没事。下一行将一个函数分配给DOM上的事件处理程序,创建从DOM到Javascript引擎的引用 - 泄漏的一半。函数体使用标签创建一个Closure--标签引用与函数一起保存,以便将来调用它。这完成了标记 - >函数(DOM - > JS)和函数 - >标记(JS - > DOM)之间的循环引用,因此2将位于内存中,直到浏览器的进程被销毁。
So in order for either line of code you mentioned to leak, it would have to be eliminating tags that had events attached like above (or data that follows a similar pattern). But, jQuery's .html(string) goes out of its way to prevent these:
因此,为了使您提到的任何一行代码泄漏,它必须消除具有上述事件附加的标记(或遵循类似模式的数据)。但是,jQuery的.html(字符串)不遗余力地阻止这些:
// Remove element nodes and prevent memory leaks
elem = this[i] || {};
if ( elem.nodeType === 1 ) {
jQuery.cleanData( getAll( elem, false ) );
elem.innerHTML = value;
}
So it's looping through all the tags inside the tag you're running .html(string) on and running cleanData() on them, which in turn does this:
所以它循环遍历标签内的所有标签,你正在运行.html(字符串)并在它们上运行cleanData(),这反过来做到这一点:
jQuery.removeEvent( elem, type, data.handle );
Thus preventing the leak.
从而防止泄漏。
So in order to leak memory with this method and not the browser built-in .innerHTML you'd have to be triggering some very obscure browser bug (seems pretty unlikely), or more likely something else is going on and you're mistaking it for jQuery's .html(string).
所以为了使用这种方法泄漏内存而不是浏览器内置的.innerHTML,你必须触发一些非常模糊的浏览器错误(似乎不太可能),或者更可能是其他东西正在发生而你却误以为对于jQuery的.html(字符串)。
#2
2
Always use .empty().html(...)
instead of just .html()
始终使用.empty()。html(...)而不仅仅是.html()
.empty()
unbinds the event listeners from the DOM objects you are about to remove, and removes them gracefully.
.empty()从您要删除的DOM对象中取消绑定事件侦听器,并正常删除它们。