Thi*_*yya 44 javascript performance jquery garbage-collection memory-leaks
jQuery中哪些标准问题或编码模式会导致内存泄漏?
我在StackOverflow上看到了一些与ajax()调用或jsonp或DOM删除相关的问题.大多数jQuery内存泄漏问题都集中在特定问题或浏览器上,在jQuery中列出标准内存泄漏模式会更好.
以下是关于SO的一些相关问题:
网上资源:
tof*_*arr 29
根据我的理解,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();
}
Run Code Online (Sandbox Code Playgroud)
在您查看内存使用情况之前,它看起来很正常.由于"_this"指针(增加i的最大值以使其更加显着),因此在页面处于活动状态时,MyObject的实例永远不会被释放.(在旧版本的IE中,它们从未被释放,直到程序退出.)由于javascript对象可能在帧之间共享(我不建议尝试这个,因为它是严重的气质.),有些情况下甚至在现代浏览器中javascript物体可以比它们的意图长得多.
在jquery的上下文中,通常存储引用以节省dom搜索的开销 - 例如:
function run(){
var domObjects = $(".myClass");
domObjects.click(function(){
domObjects.addClass(".myOtherClass");
});
}
Run Code Online (Sandbox Code Playgroud)
由于在回调函数中对它的引用,此代码将永久保留domObject(及其所有内容).
如果jquery的编写者在内部错过了这样的实例,那么库本身就会泄漏,但更常见的是它是客户端代码.
第二个示例可以通过在不再需要时显式清除指针来修复:
function run(){
var domObjects = $(".myClass");
domObjects.click(function(){
if(domObjects){
domObjects.addClass(".myOtherClass");
domObjects = null;
}
});
}
Run Code Online (Sandbox Code Playgroud)
或者再次进行查找:
function run(){
$(".myClass").click(function(){
$(".myClass").addClass(".myOtherClass");
});
}
Run Code Online (Sandbox Code Playgroud)
一个好的经验法则是在定义回调函数时要小心,并尽可能避免过多的嵌套.
编辑:正如Erik在评论中指出的那样,您也可以使用this指针来避免不必要的dom查找:
function run(){
$(".myClass").click(function(){
$(this).addClass(".myOtherClass");
});
}
Run Code Online (Sandbox Code Playgroud)
Dav*_*vin 16
我将在这里贡献一个反模式,这是"中链参考"泄漏.
jQuery的优势之一是它的链接API,它允许您继续更改,过滤和操作元素:
$(".message").addClass("unread").find(".author").addClass("noob");
Run Code Online (Sandbox Code Playgroud)
在该链的末尾,您有一个带有所有".message .author"元素的jQuery对象,但该对象返回并使用原始的".message"元素进行对象.您可以通过该.end()
方法访问它们并对它们执行某些操作:
$(".message")
.find(".author")
.addClass("prolific")
.end()
.addClass("unread");
Run Code Online (Sandbox Code Playgroud)
现在,当以这种方式使用时,泄漏没有问题.但是,如果将链的结果分配给具有较长生命周期的变量,则对较早集的反向引用将保持不变,并且在变量超出范围之前无法进行垃圾回收.如果该变量是全局变量,则引用永远不会超出范围.
例如,假设您在2008年的某篇博客文章中读到的内容$("a").find("b")
比"更有效" $("a b")
(即使它甚至不值得考虑这样的微优化).您决定需要一个页面范围的全局来保存作者列表,以便您执行此操作:
authors = $(".message").find(".author");
Run Code Online (Sandbox Code Playgroud)
现在你有一个带有作者列表的jQuery对象,但它也引用了一个jQuery对象,它是完整的消息列表.你可能永远不会使用它,甚至不知道它在那里,它占用了内存.
需要注意的是泄漏只能与选择的方法中发生新的从现有的组的元素,例如.find
,.filter
,.children
等.该文档指示当新返回集.如果链具有简单的非过滤方法.css
,那么简单地使用链接API不会导致泄漏,所以这是可以的:
authors = $(".message .author").addClass("prolific");
Run Code Online (Sandbox Code Playgroud)