3

I am working with the 'canvas' element, and trying to do some pixel based manipulations of images with Javascript in FIrefox 4.

The following code leaks memory, and i wondered if anyone could help identify what is leaking.

The images used are preloaded, and this code fragment is called once they are loaded (into the pImages array).

    var canvas = document.getElementById('displaycanvas');
    if (canvas.getContext){
        var canvasContext = canvas.getContext("2d");
        var canvasWidth = parseInt(canvas.getAttribute("width"));
        var canvasHeight = parseInt(canvas.getAttribute("height"));

        // fill the canvas context with white (only at start)
        canvasContext.fillStyle = "rgb(255,255,255)";
        canvasContext.fillRect(0, 0, canvasWidth, canvasHeight);

        // for image choice
        var photoIndex;

        // all images are the same width and height
        var imgWidth    = pImages[0].width;
        var imgHeight   = pImages[0].height;

        // destination coords 
        var destX, destY;

        // prep some canvases and contexts
        var imageMatrixCanvas               = document.createElement("canvas");
        var imageMatrixCanvasContext        = imageMatrixCanvas.getContext("2d");


        // Set the temp canvases to same size - apparently this needs to happen according 
        // to one comment in an example - possibly to initialise the canvas?
        imageMatrixCanvas.width         = imgWidth;
        imageMatrixCanvas.height        = imgHeight;

        setInterval(function() { 
            // pick an image
            photoIndex = Math.floor(Math.random() * 5);

            // fill contexts with random image
            imageMatrixCanvasContext.drawImage(pImages[photoIndex],0,0);
            imageMatrixData = imageMatrixCanvasContext.getImageData(0,0, imgWidth, imgHeight);

            // do some pixel manipulation
            // ...
            // ...

            // choose random destination coords (inside canvas)
            destX = Math.floor(Math.random() * (canvasWidth - imgWidth));
            destY = Math.floor(Math.random() * (canvasHeight - imgHeight));

            // show the work on the image at the random coords
            canvasContext.putImageData(imageMatrixData, destX, destY);
        }, 500);        
    }
stephendwolff
  • 1,382
  • 1
  • 13
  • 27
  • 2
    What browser? IE? How do you know for sure that it's leaking memory? – Matt Ball Feb 03 '11 at 22:17
  • @MattBall - i worked out it wasn't the browser exactly - afaik, it's the bridge between DOM and Javascript memory. See my responses to Martin Jespersen below. – stephendwolff Apr 18 '11 at 12:47

2 Answers2

1

Oh.. mistake. The memory lookes OK after few test.
But there is another problem.
The size of used memory by tab process is growing when changing the src property of img elements...

Src property = canvas.getContext('2d').toDataURL('image/png') (changing each time);

I've tried to "delete img.src", remove node...

j0k
  • 22,600
  • 28
  • 79
  • 90
bef
  • 11
  • 2
  • it's not really the browsers fault - just a painful example of how memory management in Javascript is actually important when dealing with large objects, and loops. Something most javascript programmers don't come across *that* often... Thanks for your comment anyway. – stephendwolff Apr 18 '11 at 12:49
  • 1
    this now looks like a question rather than an answer... anyhow, try moving any variable assignment outside the loop. it is the re-assignment that leaks the memory. For example, i ended up creating an array of source images outside my loop (so that the memory is allocated), then refer to the sources inside the loop to copy to canvases (also created outside the loop) – stephendwolff Apr 28 '11 at 10:13
0

Changing imageMatrixData = ... to var imageMatrixData = ... might help a bit, but I doubt that is the full story. But as far as i can tell imageMatrixData is a global scope variable that you assign on every interval iteration, and that cannot be healthy especially with a big chunk of data :)

I know that getImageData used to memoryleak in Chrome but that was pre version 7, not sure how it is now, and seeing as you are talking about ff4 then that is probably very irrelevant.

Martin Jespersen
  • 25,743
  • 8
  • 56
  • 68
  • 1
    Thanks for your comments Martin. I discovered that the main problem was using getImageData inside a loop (the setInterval). As far as I can gather - the previous use isn't disposed of correctly - and i think it's similar to what i've read of IE javascript memory leaks - when crossing the DOM / Javascript divide. As long as i do all my getImageData outside the loop (ie in preparation), memory doesn't seem to leak. That said - Chrome uses much much less memory for the same task... – stephendwolff Feb 05 '11 at 21:52
  • @martin-jespersen - i responded, but hadn't spotted the 'at' way of notifying you. Thus this comment! – stephendwolff Feb 08 '11 at 13:59
  • @stephenwolff: Sorry for my lacking response, but I gathered from your last response, that you had found a solution? If you still wish to use it inside the `setInterval`, you have to figure out a way of disposing it properly. Have you tried setting `imageMatrixData = null` after you are done with it? That should force explicit garbage collection. Btw, there are several big differences between a loop and `setInterval` - the biggest being that each iteration of setInterval has it's own callstack and scope. – Martin Jespersen Feb 08 '11 at 17:43
  • @martin-jespersen. Thanks - i'll give the =null a go. I'm filling a few buffers with images / masks, so am using a fair amount of memory, but as long as i do the 'getImageData' outside of setInterval, then I no longer leak any. I'm still non the wiser why Chrome uses much less, but I am using the Firefox AudioAPI for which the Chrome alternative isn't quite ready for my target platform (a mac in a gallery space) – stephendwolff Feb 27 '11 at 21:54