Click here to Skip to main content
Click here to Skip to main content

jQuery Memory Leak in UpdatePanel

By , 20 Mar 2009
 

Introduction

This article discusses how to integrate jQuery library with Microsoft AJAX.NET, in particular with <asp:UpdatePanel/> and to avoid Internet Explorer memory leak while doing so.

jQuery becomes more and more popular. However Microsoft ASP.NET and AJAX.NET provide their own framework of communicating with the server. jQuery AJAX mechanism seems clumsy and un-natural in ASP.NET environment. It's much easier to use ASP.NET UpdatePanels for AJAX functionality and use jQuery for their selectors functionality - pretty much what I understood Microsoft is planning to do. However doing so is tricky and this article explains at least some of the shortfalls of doing so.

Iteration 1 - Sample Page

Let's imagine a sample calc - page that adds 2 numbers:

<body> 
    <form id="form1" runat="server"> 
   	<asp:ScriptManager runat="server" ScriptMode=Debug> 
   	    <Scripts> 
		<asp:ScriptReference Path="~/jquery-1.2.6.debug.js" /> 
	    </Scripts> 
	</asp:ScriptManager> 
	<asp:UpdatePanel ID='up' runat="server"><ContentTemplate> 
	    <asp:TextBox ID='i1' runat="server" CssClass='num' Width='50px'/>+ 
	    <asp:TextBox ID='i2' runat="server" CssClass='num' Width='50px'/>= 
	    <asp:TextBox ID='res' runat="server" Width='50px'/> 
	    <asp:Button ID='btn' runat="server" Text='...'/> 
	</ContentTemplate></asp:UpdatePanel> 
    </form> 
</body> 
<script> 
	function add() { 
		$get('res').value = parseInt($get('i1').value) 
			+ parseInt($get('i2').value); 
	} 
	$(document).ready(function() { 
		$('.num').change(add); 
	}); 
</script> 

This page should not require much explanation if you have some familiarity with ASP.NET and jQuery:

  • We include ScriptManager and jquery script.
  • Standard form
  • We define 3 input controls, first two of which have class='num' - so we can easily find them with jQuery
  • Contents are placed in <asp:UpdatePanel> and button is provided to refresh the panel
  • Function is defined to get 2 numbers, add them up and store the result in the third input box
  • Standard jQuery mechanism is provided to attach change event so when one of the numbers gets changed, calculations are performed.

The resulting page looks like this:

The stuff initially seems to work. You can change the numbers and see the result on the screen. However try to refresh the UpdatePanel - and suddenly calculations break.

Explanation

The reason for failure after the UpdatePanel refresh is that the contents of the UpdatePanel go away along with all the events attached to them.
To solve the problem, we need to use AJAX.NET provided way of attaching events to the page (here I'm attaching only script portion):

function add() {
	$get('res').value = 
		parseInt($get('i1').value) + parseInt($get('i2').value);
}
Sys.Application.add_load(function() {
	$('.num').change(add);
});

Iteration 2 - Memory Leak

The approach suggested in iteration 1 worked for me for a while. Except eventually, I started to notice that Internet Explorer slows down. A lot. And then looking at the process monitor, I noticed that Internet Explorer would leak memory on the moderate size form like a megabyte per UpdatePanel refresh. Looking at the sIEve tool (God bless the heart of the creators), I saw that the input elements are not been destroyed:

You can see that every time I click refresh, it creates a new set of input elements without destroying the previous ones.

Explanation

Googling it for a while I noticed that Internet Explorer memory leak is a sore subject for a lot of developers. Most of the complaints were identified as either pseudo leak (memory is actually released but you need a complete page refresh to see it) or as closures.

The closure is an interesting topic. It refers to the JavaScript event attached to the DOM element. Apparently Internet Explorer uses 2 garbage collectors - one for DOM and another for JavaScript. There are some semantics involved but the bottom line is that if you attached an event to the DOM object, then neither garbage collector would be able to get rid of the involved objects/DOM elements. I strongly encourage you to read more about closures on the WEB.

Well the jQuery is all about closures. They are nice enough to attach to window.unload and cleanup when the page gets unloaded, but they have no idea regarding UpdatePanel. Something needs to be done to cleanup jQuery when UpdatePanel is about to be refreshed.

Iteration 3 - jQuery Cleanup Plugin

UpdatePanel does provide cleanup hooks. When it's about to throw an element away, it checks to see if there is a element.dispose function. If such a function exists, then it will be executed.

So I ended up creating the following jQuery plugin to take care of the situation:

(function($) {
	$.fn.Disposable = function(cln) {
		return this.each(function() {
			var el = this;
			if (!el.dispose) {
				el.dispose = cleanup; // will be called by 
						    // Microsoft for cleanup
				$(window).bind("unload", cleanup);
			}
			function cleanup() {
				if (!el)
					return;
				$(el).unbind();
				$(window).unbind("unload", cleanup);
				el.dispose = null;
				el = null;
			};
		});
	};
})(jQuery);
function add() {
	$get('res').value = 
		parseInt($get('i1').value) + parseInt($get('i2').value);
}
Sys.Application.add_load(function() {
	$('.num').change(add).Disposable();
});

As you can see, this jQuery plugin attaches a cleanup() function to element.dispose. Whenever element.dispose is being called, all the jQuery events will be unbound from the element and allow garbage collector to reclaim all the objects.

Summary 

The code I'm discussing is actually part of another library I posted a while ago at jQuery Based Ajax.Net library. You are welcome to download that project and browse the code at your leisure.

History

  • 20th March, 2009: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

gstolarov
United States United States
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
Hint: For improved responsiveness ensure Javascript is enabled and choose 'Normal' from the Layout dropdown and hit 'Update'.
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralHi! Please help me.. thank you.memberYU-TIEN25 Aug '09 - 23:20 
GeneralRe: Hi! Please help me.. thank you.membergstolarov26 Aug '09 - 3:53 
GeneralMy vote of 1memberkeertiraj5559 Apr '09 - 3:35 
GeneralRe: My vote of 1membergstolarov9 Apr '09 - 15:35 
GeneralRe: [SORRY] My vote of 1memberkeertiraj55511 Apr '09 - 0:14 
Generalthis breaks custom server control [modified]memberterrytsay20 Mar '09 - 20:59 
GeneralRe: this breaks custom server controlmembergstolarov21 Mar '09 - 5:37 
GeneralRe: this breaks custom server controlmemberterrytsay23 Mar '09 - 9:28 
GeneralAlternative to using plugin if using jQuery 1.3 or highermemberTheYo20 Mar '09 - 13:15 
GeneralRe: Alternative to using plugin if using jQuery 1.3 or highermembergstolarov20 Mar '09 - 13:51 
GeneralRe: Alternative to using plugin if using jQuery 1.3 or highermembergstolarov23 Mar '09 - 4:31 
I just tried live() and it does seems to do the trick - thanks again. Unfortunately, "change" event (along with blur, focus, mouseenter, mouseleave, submit) are currently not supported. They also have some limitations on how you can call it. As it currently stands I wouldn't be able to use it in my code, however once it develops it probably will be something promising.
GeneralRe: Alternative to using plugin if using jQuery 1.3 or highermemberTheYo23 Mar '09 - 8:00 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web02 | 2.6.130516.1 | Last Updated 20 Mar 2009
Article Copyright 2009 by gstolarov
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid