从我记得的一个不太遥远的过去,Javascript解释器在面对循环引用时遭遇了内存泄漏问题.
在最新的浏览器中仍然如此吗?(例如Chrome,FF 3.5等)
jQuery.data与原始expando属性(可以分配给DOM节点的任意属性)的一个被吹捧的优点是jQuery.data "不受循环引用的影响,因此没有内存泄漏".谷歌的一篇名为"优化JavaScript代码"的文章详细介绍:
Web应用程序最常见的内存泄漏涉及JavaScript脚本引擎和实现DOM的浏览器的C++对象之间的循环引用(例如,在JavaScript脚本引擎和Internet Explorer的COM基础结构之间,或者在JavaScript引擎和Firefox XPCOM基础结构之间).
它列出了两个循环引用模式的示例:
DOM元素→事件处理程序→闭包范围→DOM
DOM元素→通过expando→中间对象→DOM元素
但是,如果DOM节点和JavaScript对象之间的引用循环产生内存泄漏,这是否意味着任何非平凡的事件处理程序(例如onclick
)都会产生这样的泄漏?我不知道事件处理程序如何避免引用循环,因为我看到它的方式:
DOM元素引用事件处理程序.
事件处理程序引用DOM(直接或间接).在任何情况下,几乎不可能避免window
在任何有趣的事件处理程序中引用,而不是编写setInterval
从全局队列中读取操作的循环.
有人可以提供JavaScript↔DOM循环引用问题的精确解释吗?我想澄清的事情:
什么浏览器受影响?jQuery源代码中的评论专门提到IE6-7,但谷歌文章表明Firefox也受到了影响.
expando属性和事件处理程序在内存泄漏方面有何不同?或者这些代码片段是否容易受到同类内存泄漏的影响?
// Create an expando that references to its own element.
var elem = document.getElementById('foo');
elem.myself = elem;
// Create an event handler that references its own element.
var elem = document.getElementById('foo');
elem.onclick = function() {
elem.style.display = 'none';
};
Run Code Online (Sandbox Code Playgroud)如果页面由于循环引用而泄漏内存,则泄漏是否会持续到整个浏览器应用程序关闭,或者窗口/选项卡关闭时是否释放内存?
我有一个GreaseMonkey脚本,适用于使用框架作为其界面不可分割的一部分的网站.这个脚本像筛子一样泄漏内存,我相信这是因为我在其中一个框架中使用了addEventListener.很简单,我附加了各种事件监听器,然后框架重新加载并附加事件监听器,然后当您与此框架中的各种元素或其他元素交互时,框架会重新加载数周或数千次迭代.到最后,Firefox已经从大约300M的内存增加到2G(或者在它到达之前崩溃).
我在某地读到,执行整页重新加载将允许FireFox的垃圾收集例程启动并从孤立的事件处理程序中恢复所有内存,当我在脚本运行一段时间后,在内存大约10秒内按F5时就足够了回到300M.不幸的是,这打破了网站中的一个不同的框架(一个非常流行的聊天窗口),所以虽然它确实似乎证实我怀疑addEventListener是责备,但它并不是一个真正的解决方案.
我还能做些什么来在不强制刷新整页的情况下正确释放内存吗?
(目前使用GM 1.5和FF 17,但问题是自GM 0.8/FF 4以后就存在这个问题.)