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:
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?
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.
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.
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.
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.
I have used 3 different types of approaches...
First. Did add a set of images and left the garbage collection to browser.
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); }
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); }
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.
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With