Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript + IMG tags = memory leak. Is there a better way to do this?

I've got a web page that's using jquery to receive some product information as people are looking at things and then displays the last product images that were seen. This is in a jquery AJAX callback that looks pretty much like this:

if(number_of_things_seen > 10) {
  $('#shots li:last-child').remove();
}

$('<li><img src="' + p.ProductImageSmall + '"></li>').prependTo('#shots');

However, it seems to leak quite a bit of memory. Visually, it does the right thing, but the footprint grows indefinitely.

Safari's DOM inspector shows the DOM is how I would expect it to be, but it seems to maintain references to every image that it has displayed (as seen in this screenshot in case anyone is interested).

I've added

$('#shots li:last-child img').remove();

to the removal statement to no noticable effect.

Is there some magic necessary to let the browser release some of this stuff?

like image 424
Dustin Avatar asked Dec 03 '08 06:12

Dustin


People also ask

Which of the following can be done to reduce memory leakage?

Use reference objects to avoid memory leaks ref package, you can work with the garbage collector in your program. This allows you to avoid directly referencing objects and use special reference objects that the garbage collector easily clears. The special subclasses allow you to refer to objects indirectly.

Are there memory leaks in JavaScript?

The JavaScript engine allocates memory when you create objects and variables in your application, and it is smart enough to clear out the memory when you no longer need the objects. Memory leaks are caused due to flaws in your logic, and they make way for poor performance in your application.

How do I find memory leaks in web application?

Start with metrics such as page load times, HTTP request times, and Core Web Vitals – time to the first byte, first contentful paint. If you use Sematext Experience you'll see a number of other useful metrics for your web applications and websites there. However, metrics themselves are only a part of the whole picture.


4 Answers

Browsers are notorious for memory leaks. It sounds like the problem occurs when the page is left running for a long time. How about refreshing the page before it runs out of memory?

window.setTimeout("location.reload()",1000*60*60);//refresh in an hour
like image 137
Rob Colburn Avatar answered Oct 05 '22 07:10

Rob Colburn


Can you try changing the src of the last-child and see if that makes a difference? You can then move that element to be the first child

//not tested

var $list=$('#shots>li');
$list.filter(':last-child').children('img')
.attr('src', p.ProductImageSmall)
.parent()
.insertBefore( $list.eq(0) );
like image 36
redsquare Avatar answered Oct 05 '22 07:10

redsquare


From the Mozilla Developer Center on removeChild():

The removed child node still exists in memory, but is no longer part of the DOM. You may reuse the removed node later in your code, via the oldChild object reference.

This is the key - reuse the removed child, instead of repeatedly making a new one.

// I'm sure there is a nicer way to do it in jQuery
if(number_of_things_seen > 10) {
  var shots = document.getElementById("shots");
  var li    = shots.getElementsByTagName("LI");
  var move  = shots.removeChild(li[li.length-1]);
  move.getElementsByTagName("IMG")[0].src = p.ProductImageSmall;
  shots.insertBefore(move, li[0]);
}
like image 35
Tomalak Avatar answered Oct 05 '22 05:10

Tomalak


Is the footprint really a problem?

I suspect that Safari caches all images as long as you stay on the same site and there's nothing you can do about it. If you're lucky Safari releases not-needed objects after some limit is reached.

The reason for this behaviour is, that Safari thinks it's likely that those images are used a second time, and therefore it caches them.

like image 44
Georg Schölly Avatar answered Oct 05 '22 06:10

Georg Schölly