Bug Tracker

Opened 16 years ago

Closed 16 years ago

Last modified 12 years ago

#1233 closed bug (fixed)

IE pseudo memory leak

Reported by: jackysee Owned by:
Priority: minor Milestone: 1.1.3
Component: event Version: 1.1.2
Keywords: Cc:
Blocked by: Blocking:

Description

I'm making a page which would make ajax called periodically. The page itself would not be fresh. The callback will remove all table rows and refresh them to new one to the new data.

Regardless of the ajax part, I found that there will be memory leak in IE when using jQuery to clear table rows and insert again. MS called it 'pseudo leak' as it would be cleared after page refresh. (some detail: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/IETechCol/dnwebgen/ie_leak_patterns.asp ) But as the page will stay, such leak would gradually increase the browser's memory.

Following is an simple example demonstrating it. I use the tools IESieve (http://home.wanadoo.nl/jsrosman/) to detect IE's memory and dom usage. You can repeat the test by:

  1. open IESieve and load the test page
  2. click on 'refreshes all rows', you should notice increase in dom object in use.
  3. click on 'remove all rows', the dom usage is not decreased

OR

  1. click on 'start interval', you will see the memory and dom usage both increase
<html>
	<head>
		<title>Test Mem Leak in IE6</title>
		<script type="text/javascript" src="jquery-1.1.2.js"></script>
		<script type="text/javascript">
			var datas = [
				[1,2,3,4,5],
				[1,2,3,4,5],
				[1,2,3,4,5],
				[1,2,3,4,5],
				[1,2,3,4,5],
				[1,2,3,4,5]
			];
			
			
			$(document).ready(function(){
				$("#remove").click(removeAllRows);
				$("#refresh").click(refreshRows);
				$("#interval").click(startRefresh);
				
			});
			
			function startRefresh(){
				var interval = setInterval(refreshRows,5*1000);
			}
			
			function refreshRows(){
				removeAllRows();
				for(var i=0; i<datas.length; i++){
					var tr = document.createElement("tr");
					for(var j=0; j<datas[i].length; j++){
						var td = document.createElement("td");
						var d = datas[i][j]*Math.floor(Math.random()*100+1);
						td.innerHTML = 
							"<a href='#' onclick='return false;'>"+d+"</a>" +
							"<input type='button' onclick='buttonClick(this)' value='"+datas[i][j]+"'/>";
						$(tr).append(td);
						td = null;
						d = null;
					}
					var tb = $("#test>tbody").append(tr);
				}
			}
			
			function removeAllRows(){
				var tb = $("#test>tbody")
					.find("*").unbind().end()
					.html("");
			}
			
			function buttonClick(obj){
				obj.value = 'btn';
			}
			
			
		</script>
	</head>
	<body>
		<table id="test" border="1">
			<thead>
				<tr>
					<th>th1</th>
					<th>th2</th>
					<th>th3</th>
					<th>th4</th>
					<th>th5</th>
				</tr>
			</thead>
			<tbody>
				
			</tbody>
		</table>
		<input type="button" value="remove all rows" id="remove"/>
		<input type="button" value="refresh all rows" id="refresh"/>
		<input type="button" value="start interval" id="interval"/>
	
	</body>

</html>

Attachments (1)

memleak.jpg (75.4 KB) - added by jackysee 16 years ago.

Download all attachments as: .zip

Change History (5)

Changed 16 years ago by jackysee

Attachment: memleak.jpg added

comment:1 Changed 16 years ago by brandon

Priority: majorminor

One way around this in your app and apps like yours is to invoke the IE garbage collector by calling the GarbageCollect function. You would want to do this every so often are important clicks/exchanging. Calling this method should release any memory that IE would normally release on refresh.

Just call it like this:

GarbageCollect();

comment:2 Changed 16 years ago by pbludov

This pseudo-leak comes from jQuery.event.add() function. Last line of this function is

this.global[type].push( element );

jQuery.event.remove() does not remove the element from global queue (I think it's a bug). This reference will be removed only in the "page unload" handler. The workaround is to add some code to the end of jQuery.event.remove(), like

} else if ( events[type] ) { ...

var els = this.global[type]; var rem = []; for (i = 0; i < els.length; ++i)

if (els[i] != element)

rem.push(els[i]);

this.global[type] = rem;

}

and explicitly unbind all elements before a new content will be loaded. For example:

$.fn.extend({

myLoad : function(url, params, callback, ifModified) {

return this

.each(function(){ $(this.all).unbind(); }) .load(url, params, callback, ifModified);

}

comment:3 Changed 16 years ago by carlos.aguay

I have the same problem... This bug has already been reported in #1136

comment:4 Changed 16 years ago by brandon

Resolution: fixed
Status: newclosed

This is now fixed in Rev [2011].

Note: See TracTickets for help on using tickets.