[英]javascript memory leak in IE6 with basic jquery ui plugin
首先,我閱讀並廣泛研究了這個問題。 我已經關注了帶有jquery UI的票證。 而且我知道解決該錯誤的方法,但是我對為什么會發生這種情況非常好奇。 我認為該錯誤是由於關閉導致的,但是我的javascript-fu並不熟練。
我認為,jQuery UI團隊要做的事情要比花精力在IE6錯誤上更好。 因此,我想將其介紹給一般javascript公眾。
以下是一個測試案例:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>jquery ui memory leak test</title>
<script type="text/javascript" src="jquery-1.5.js"></script>
<script type="text/javascript" src="jquery.ui.widget.js"></script>
<script type="text/javascript">
(function($) {
$.widget("ui.test", {
_create: function() {
}
});
$(document).ready(function() {
for (var i = 0; i < 1; i++) {
$("#container").append("<div id='inner'></div>");
$("#inner").test();
$("#inner").test("destroy");
$("#container").empty();
};
});
})(jQuery);
</script>
</head>
<body>
<div id="container">
</div>
</body>
</html>
我已經測試過使用jquery 1.4.4和1.5以及jquery-ui-1.8.9和jquery-ui master的所有組合(在撰寫本文時),但是它們都產生相同的結果。
我的測試窗口小部件相信是您能獲得的最簡單的窗口小部件。
如果使用sIEve進行測試,則可以發現泄漏。 否則,將計數器增加到1000左右,您會發現內存增加非常容易。 Microsoft提供的另一種工具也可以用來檢測泄漏。
因此,泄漏是由於小部件的_createWidget
方法中的自定義事件綁定_createWidget
:
var self = this;
this.element.bind( "remove." + this.widgetName, function() {
self.destroy();
});
因此,如果我將這些注釋掉,則不會泄漏。 我使用1.8.9而不是master,因為1.8.9的小部件代碼似乎更簡單(master有所更改)。
現在,如果我將同一事件完全綁定到小部件外部,則也不會泄漏。 例如,我將在創建小部件之后但銷毀之前插入以下代碼:
$("#inner").bind("remove.test", function() {});
我有意添加了一個no-op函數,但是回調函數內部沒有關系。 您可能會爭辯說,由於之后我要手動進行銷毀,因此不需要綁定。 但這不是重點。
所以我的問題是,為什么原始代碼和來自小部件代碼的綁定調用會泄漏? 我懷疑這是由於關閉導致的,但我無法解釋。
有人可以解釋嗎?
據我了解,問題是當JS和DOM之間存在循環引用時,當JS變量指向DOM對象,並且該DOM對象具有指向JS變量的屬性(通常是事件處理程序)時,就會發生此問題。 。 上面帶有.bind()的示例似乎可以做到這一點。 顯然,IE在其垃圾回收過程中使用了引用計數,並且不會收集循環引用。
我至少看到兩個MSDN博客將其歸咎於JavaScript,並且基本上建議避免使用閉包,這顯然不是很有用,但是這里有一些非Microsoft / MSDN文章討論了該問題並給出了解決方法:
http://laurens.vd.oever.nl/weblog/items2005/closures/
很抱歉,我無法提供造成此問題的原因的說明,但我正在努力解決此問題,以防止發生這種令人討厭的泄漏。
在頁面中包含jquery和jquery-ui之后,我添加了以下代碼:
var origCreateWidget = $.Widget.prototype._createWidget;
$.Widget.prototype._createWidget = function( options, element ) {
var origBind = $.fn.bind;
var widget = this;
$.fn.bind = function( type, func ) {
if( typeof( type ) === "string" && type.indexOf( "remove." ) === 0) {
// ignore the remove events
}
else {
origBind.apply( this, arguments );
}
return this;
}
var res = origCreateWidget.call( this, options, element );
$.fn.bind = origBind;
return res;
};
另外,發生窗口卸載事件時,我將其稱為destroy
。 完成這些更改后,sIEve不會報告任何泄漏,並且Windows任務管理器在瀏覽包含可排序小部件的頁面時會顯示恆定的內存消耗。
經過數小時的搜索和測試,我仍然無法弄清泄漏的真正原因。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.