6

Systematically updating src of IMG. Memory leak.

I am currently updating an image every x sec. A few ways I thought of doing this were as follows:

Take One:

var url ="...";
$('#ImageID').attr('src', url);

Now this works perfectly changes the image but causes a memory leak.

Take Two:

So it is creating DOM elements, so I attempted the following.

<div id="ImageHolder">

</div>

var image - "..."; //Obv actual image in working.

$('#ImageHolder').empty();
$('#ImageHolder').html(image);

Now this works but causes a flicker when it changes which is unliked. Now with two images and swapping them at intervals works fine, but I want to stay as low on bandwidth as possible.

Edit 1:

My Code:

<form name="selected">
<input type="hidden" name="map" />
</form>

<img id="MyMaps" src="http://localhost/web/blank.png" alt="" />


<script type="text/javascript">
var locate = window.location;
var uri = document.selected.map.value;

var MyHost = window.location.hostname;
    function delineate2(name) {
        totheleft= uri.indexOf("maps/") + 5;
        totheright= uri.lastIndexOf("&");
        return (uri.substring(totheleft, totheright));
    }

    function loadImage() {
        var CurrentMap = delineate2(name);
        var url = 'http://' + MyHost+ '/map/' + CurrentMap+ '/image?' + new Date().getTime();

        $('#MyMaps').attr('src', url);

        setTimeout(loadImage, 10000);
    }
</script>

Has anyone done something similar and found a working solution, or how can I go about preventing the memory leak / flickering when the image updates?

Sphvn
  • 5,247
  • 8
  • 39
  • 57

4 Answers4

3

I believe that your "take one" should work. There should be no memory leak. You're overwriting the src tag every time around - if you hold no other references to old images, they should get garbage collected. I'm seeing this problem in FF and Chrome. Chrome tells me that JS memory usage is constant, the memory must be lost somehwere else. I have opened a Chrome bug: https://code.google.com/p/chromium/issues/detail?id=309543 In case you want to put in your weight as well and maybe star the bug :)

distributed
  • 366
  • 4
  • 13
3

I have used different methods to solve this problem, none of them works. It seems that memory leaks when img.src = base64string and those memory can never get released. Here is my solution.

fs.writeFile('img0.jpg', img_data, function (err) {
    // console.log("save img!" );
});
document.getElementById("my-img").src =  'img0.jpg?'+img_step;
img_step+=1;

My Electron app updating img every 50ms, and memory doesn't leak. Forget about disk usage. Chrome's memory management piss me off.

Keven Sun
  • 41
  • 2
2

5 years old question yet it still 'hot' for me, I want to share the very same problem I just faced.

The "take one" approach maybe is the very first approach every programmer used to change the image source, but till now ( 5 years after this question posted ) the problem is still occurred, change the <img> 'src' frequently and you can see on windows task manager that your browser became greedy. The "take two" create flicker, and it is rarely acceptable. Fortunately, html5 comes with <canvas>, so I try to use <canvas> to overcome this problem.

var canvas = document.getElementById("mycanvas");
var ctx = canvas.getContext("2d");
img = new Image();
img.onload = function () {
    ctx.drawImage(img, 0, 0);
    img.src = "";
}
img.src = "data:image/png;base64," + stringSource;

The new problem found, <canvas> different from <img>, it will not automatically resize and 'fit'. We have to manually resize the image to fit the canvas and keep the ratio. Below is my code to resolve the problem

var canvas = document.getElementById("mycanvas");
var ctx = canvas.getContext("2d");
img = new Image();
img.onload = function () {
    var imageWidth = canvas.width;
    var imageHeight = canvas.height;
    var xPosition = 0;
    var yPosition = 0;
    var proportion = 1;
    var padding = 2;
    if ((img.width / canvas.width) > (img.height / canvas.height)) {
        proportion = img.width / canvas.width;
    }
    else {
        proportion = img.height / canvas.height;
    }
        imageWidth = img.width / proportion;
        imageHeight = img.height / proportion;
        xPosition = (canvas.width - imageWidth) / 2;
        yPosition = (canvas.height - imageHeight) / 2;
        ctx.drawImage(img, 0, 0, img.width, img.height, xPosition+padding, yPosition+padding, imageWidth-2*padding, imageHeight-2*padding);
            img.src = "";
    }
    img.src = "data:image/png;base64," + stringSource;

Hope it will help any one who face the same problem.

2

I have never thought of doing this like your fist method.. interesting. I can imagine that it causes a memory leak because every single image is kept in memory because nothing is actually removed. Thats just a guess though.

I would recomend sticking to the second method but modifying it so solve the flicker, like fading between images. A good jQuery plugin to look at would be the jQuery Cycle Plugin

If that plugin doesn't do it for you or you want to keep the code small, jQuery also has some animation functions built in. fadeIn() and fadeOut() may be of interest.

Something like this might work better.

 <div id="ImageHolder">

</div>

var image - "..."; //Obv actual image in working.

function loadImage() {

choose your image however you want to, preferably a preloaded image.

$('#ImageHolder').fadeOut('fast');
$('#ImageHolder').html(image);
$('#ImageHolder').fadeIn('fast');
setTimeout(loadImage, 10000);
}

I believe a shorter way to do this might be: (also delay() may be optional, I just put it there in case you need it.)

$('#ImageHolder').fadeOut('fast').html(image).delay('100').fadeIn('slow');

Additionally there may be a delay for the image to load if it hasn't been preloaded. I'm not 100% sure how to do that off the top of my head so a quick google seach came up with this: http://engineeredweb.com/blog/09/12/preloading-images-jquery-and-javascript

WalterJ89
  • 1,025
  • 2
  • 7
  • 24
  • Interesting approach, Will give it a try was attempting switching between 2 absoulte div's so as it clears the DOM the 2nd div is the one in view and vice versa. – Sphvn Sep 10 '10 at 05:43
  • added some stuff about preloading, may make it cleaner looking – WalterJ89 Sep 10 '10 at 06:05
  • Yes the preload is a good idea, am currently testing will be waiting several hours but, trying a process running a .clear(); on the ImageID which seems to hold down the memory usage, but can't be certain just yet. Running them at 30ms updates to really push this thing. – Sphvn Sep 10 '10 at 06:05
  • Turns out there is an IE8 memory leak with XHR requests in jquery. Patching it completely solved this problem without having to play with the image. There are some tickets / notes on it on the jquery forums. (1.4.x) – Sphvn Sep 22 '10 at 04:53