JavaScript memory leak in IE6 with basic jquery ui plugin

First, I carefully and thoroughly studied this issue. There is already a ticket with jquery UI that I am following. And I know the way around this error, but I am very curious why this is happening. I believe the error is related to closing, but my javascript-fu is not an expert.

I believe the jquery UI team has better options than wasting energy on IE6 error. So I wanted to bring this to the general public of javascript.

The following is a test case:

<!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> 

I tested all combinations of jquery 1.4.4 and 1.5 and jquery-ui-1.8.9 and jquery-ui master (from the moment of writing), but they all give the same result.

My test widget, I think, is the easiest you can get.

If you test with sIEve , you might find a leak. Otherwise, increase the counter to about 1000, and you will see that increasing the memory is quite easy. There is another tool from Microsoft that you can also use to detect leaks.

Thus, the leak is associated with the binding of a custom event in the _createWidget widget _createWidget :

 var self = this; this.element.bind( "remove." + this.widgetName, function() { self.destroy(); }); 

So, if I comment on this, there will be no leak. I use 1.8.9, not master, as the 1.8.8 code seems simpler (the wizard has changed a bit).

Now, if I even bind the same event outside the widget, there is no leak either. For example, after creating the widget, I have to insert the following code, but before destroying it:

 $("#inner").bind("remove.test", function() {}); 

I purposefully added a no-op function, but it doesn't matter what's inside the callback function. You could argue, since after that I destroy manually, no binding is required. But this is not the point.

So my question is: why does the source code, the call of the binding from the widget code, flow? I suspect this is due to the closure, but I cannot explain it.

Can someone explain this?

+4
source share
2 answers

As I understand it, the problem arises when there is a circular reference between the JS and the DOM, when the JS variable points to the DOM object and that the DOM object has a property (or, as a rule, an event handler) that points to the JS variable. Your example above with .bind () seems to do this. Obviously, IE uses reference counting in the garbage collection process, and circular links are not collected.

I have seen at least a few MSDN blogs that blamed it on JavaScript and basically recommended avoiding closures, which is clearly not very useful, but here are some non-Microsoft / MSDN articles that discuss the problem and provide some workarounds

http://laurens.vd.oever.nl/weblog/items2005/closures/

http://www.ibm.com/developerworks/web/library/wa-memleak/

JavaScript shutdown and memory leak

+2
source

Sorry I cannot explain the cause of this problem, but I worked on a workaround to prevent this rather nasty leak.

After enabling jquery and jquery-ui on my page, I added the following code:

 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; }; 

In addition, I call destroy when a window unload event occurs. After these changes, sIEve does not report any leaks, and the Windows task manager shows constant memory consumption when navigating pages containing a sortable widget.

After hours of searching and testing, I still could not understand the cause of the leak.

0
source

Source: https://habr.com/ru/post/1339765/


All Articles