jQuery中哪些标准问题或编码模式会导致内存泄漏?
我在StackOverflow上看到了一些与ajax()调用或jsonp或DOM删除相关的问题。大多数jQuery内存泄漏问题都集中在特定问题或浏览器上,在jQuery中列出标准内存泄漏模式会更好。
以下是关于SO的一些相关问题:
网络上的资源:
答案 0 :(得分:28)
据我所知,javascript中的内存管理是通过引用计数完成的 - 虽然对象的引用仍然存在,但它不会被释放。这意味着在单个页面应用程序中创建内存泄漏是微不足道的,并且可以绊倒来自java后台的使用。这不是JQuery特有的。以下面的代码为例:
function MyObject = function(){
var _this = this;
this.count = 0;
this.getAndIncrement = function(){
_this.count++;
return _this.count;
}
}
for(var i = 0; i < 10000; i++){
var obj = new MyObject();
obj.getAndIncrement();
}
在您查看内存使用情况之前,它看起来很正常。由于“_this”指针(增加i的最大值以使其更加显着),因此在页面处于活动状态时,MyObject的实例永远不会被释放。 (在旧版本的IE中,它们从未被释放,直到程序退出。)由于javascript对象可能在帧之间共享(我不建议尝试这个,因为它是严重的气质。),有些情况下甚至在现代浏览器中javascript对象可以比它们的意图长得多。
在jquery的上下文中,通常存储引用以节省dom搜索的开销 - 例如:
function run(){
var domObjects = $(".myClass");
domObjects.click(function(){
domObjects.addClass(".myOtherClass");
});
}
由于在回调函数中对它的引用,此代码将永远保留domObject(及其所有内容)。
如果jquery的编写者在内部错过了这样的实例,那么库本身就会泄漏,但更常见的是它是客户端代码。
第二个例子可以通过在不再需要时明确清除指针来修复:
function run(){
var domObjects = $(".myClass");
domObjects.click(function(){
if(domObjects){
domObjects.addClass(".myOtherClass");
domObjects = null;
}
});
}
或再次进行查找:
function run(){
$(".myClass").click(function(){
$(".myClass").addClass(".myOtherClass");
});
}
一个好的经验法则是在定义回调函数时要小心,并尽可能避免过多嵌套。
编辑:正如Erik的评论中指出的那样,您也可以使用this指针来避免不必要的dom查找:
function run(){
$(".myClass").click(function(){
$(this).addClass(".myOtherClass");
});
}
答案 1 :(得分:16)
我会在这里贡献一个反模式,这是&#34;中链参考&#34;泄漏。
jQuery的优势之一是它的链接API,它允许您继续更改,过滤和操作元素:
$(".message").addClass("unread").find(".author").addClass("noob");
在该链的末尾,您有一个jQuery对象,其中包含所有&#34; .message .author&#34;元素,但 对象引用并反对原始&#34; .message&#34;元素。您可以通过.end()
方法与他们联系并为他们做点什么:
$(".message")
.find(".author")
.addClass("prolific")
.end()
.addClass("unread");
现在以这种方式使用时,泄漏没有问题。但是,如果将链的结果分配给具有较长生命周期的变量,则对较早集的反向引用将保持不变,并且在变量超出范围之前无法进行垃圾回收。如果该变量是全局变量,则引用永远不会超出范围。
例如,让我们说你在2008年的一篇博客文章中读到$("a").find("b")
更高效&#34;比$("a b")
(即使它甚至不值得考虑这样的微优化)。您决定需要一个页面范围的全局来保存作者列表,以便您执行此操作:
authors = $(".message").find(".author");
现在你有一个带有作者列表的jQuery对象,但它也引用了一个jQuery对象,它是完整的消息列表。你可能永远不会使用它,甚至不知道它在那里,它会占用记忆。
请注意,泄漏只能通过从现有集合中选择 new 元素的方法进行,例如.find
,.filter
,.children
等。 docs指示何时返回 new 集。如果链具有简单的非过滤方法(如.css
),那么简单地使用链接API不会导致泄漏,所以这没关系:
authors = $(".message .author").addClass("prolific");