Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I prevent memory leaks when removing images in the DOM?

There is a known bug in webkit that when you remove an image from the DOM, it doesn't free the memory associated with it.

This is an issue with single page apps that often load images.

Various suggested solutions are:

  • Remove image src attribute before removing the image from the DOM
  • Set image src to " " before removing the image from the DOM
  • Set the image to a single pixel image before removing the image from the DOM
  • Create a limited number of image elements and keep recycling them

The first 3 methods don't work for me. The main drawback to recycling image elements is that it means writing lots of code to manage that. I'm loading new HTML via AJAX that may contain images, so I don't necessarily know the number of images that will be loaded.

Are there any other work arounds to fix this problem?

like image 251
andyuk Avatar asked Dec 13 '12 11:12

andyuk


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.

How do we avoid memory leaks in closures?

Only capture variables as unowned when you can be sure they will be in memory whenever the closure is run, not just because you don't want to work with an optional self . This will help you prevent memory leaks in Swift closures, leading to better app performance.

What could be the possible cause of memory leaks?

In computer science, a memory leak is a type of resource leak that occurs when a computer program incorrectly manages memory allocations in a way that memory which is no longer needed is not released. A memory leak may also happen when an object is stored in memory but cannot be accessed by the running code.

Does Closure cause memory leak?

In simple terms, a closure is an inner function that has access to the outer function's scope. In the example above, largeArray is never returned and cannot be reached by garbage collector, significantly increasing its size through repeated calls of inner functions, resulting in a memory leak.


2 Answers

I have used 3 different types of approaches...

First. Did add a set of images and left the garbage collection to browser. enter image description here

It definitely garbage collected, but after a while, making sure that there exists no need for the images which have been created.

Second. Used a data:URI patterns for the src for images.

var s = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==";  for (var i = 0; i < 100; i++){     var img = document.createElement("img");     img.src = s; document.getElementById("myList1").appendChild(img); setTimeout(function(){img = null;}, 1000); } 

enter image description here

This looked similar, though a bit better for me as I was watching in front of my browser and observed a lesser memory was used, and garbage collection was almost the same as above.

Third. Did garbage collection in code.

var s = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==";  for (var i = 0; i < 100; i++){     var img = document.createElement("img");     img.src = "dot.png";  // or the other, both mean the same here.     img.src = s; document.getElementById("myList1").appendChild(img); setTimeout(function(){img = null;}, 1000); } 

enter image description here

In this short time of testing, I believed that the last approach worked better, as it was almost freeing the space up immediately without waiting to see if there was any need for the referenced images further.

All in all, You better use garbage collection by yourself, when you absolutely feel like something must be freed off.

like image 193
Siva Tumma Avatar answered Oct 05 '22 14:10

Siva Tumma


A basic image pool should allow you to recycle img elements for re-use. Since you don't know how many images there will be total ahead of time, just have the pool size expand as necessary.

Something like this should work:

    function getImg( id, src, alt ) {         var pool = document.getElementById( 'image_pool' );         var img = ( pool.children.length > 0 ) ? pool.removeChild( pool.children[0] ) : document.createElement( 'img' );         img.id = id;         img.src = src;         img.alt = alt;         return img;     }     function recycleImg( id ) {         var img = document.getElementById( id );         document.getElementById( 'image_pool' ).appendChild( img.parentNode.removeChild( img ) );     } 

Place a hidden "image_pool" container on your page somewhere, to hide the recycled images between usage:

<div id="image_pool" style="display:none;"></div> 

Then any time you need a new img element, call:

document.getElementById( 'some_element_id' ).appendChild( getImg( 'my_image_id', 'images/hello.gif', 'alt_text' ) ); 

And when you are done with it:

recycleImg( 'my_image_id' ); 

jQuery alternative

    function getImg( id, src, alt ) {         var img;         if( $("#image_pool").children().length > 0 ) {             return $("#image_pool img:first-child").attr( { 'id': id, 'src': src, 'alt': alt } ).detach();         }         return $( "<img />'" ).attr( { 'id': id, 'src': src, 'alt': alt } );     }     function recycleImg( id ) {         $( "#" + id ).detach().appendTo( $("#image_pool") );     } 

When you need a new img element:

getImg( 'my_image_id', 'images/hello.gif', 'alt_text' ).appendTo( $( "#some_element_id" ) ); 

(recycling works the same as above)

like image 34
paulscode Avatar answered Oct 05 '22 14:10

paulscode