Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Memory leaks when manipulating images in Chrome

I encountered the following 2 (huge!) memory leaks in Chrome:

  1. When editing the 'src' of an existing image, with new bytes
  2. When using clone() to clone an image

Note that in Internet Explorer there is NO memory leak what so ever!

Some background: I'm working on a project where an external camera provides a live feed of images (let's say 100 frames per second).

The main 3 functionalities of the project are:

  1. play live feed
  2. record live feed
  3. show recorded feed

You are welcome to download the following standalone code (simply save it as "leak.html" and execute it), and see for yourself:

<!DOCTYPE html>
<html>
    <body>
        <canvas id="meCanvas" width="526" height="395"></canvas>

        <script src="http://code.jquery.com/jquery-2.0.3.min.js" type="text/javascript"> </script>
        <script>
            var meContext = document.getElementById("meCanvas").getContext("2d");

            // Bytes array representing a chair image
            var chairImgSrc = "data:image/png;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAoHBwkHBgoJCAkLCwoMDxkQDw4ODx4WFxIZJCAmJSMgIyIoLTkwKCo2KyIjMkQyNjs9QEBAJjBGS0U+Sjk/QD3/2wBDAQsLCw8NDx0QEB09KSMpPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT3/wAARCAHgAoADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwCtijFLRUlMAKQUUtAg70lHelpgJRS0UCDNAoHFLQFw70UUZoAB1pTSUtIApaTNLmmAUopKWkAUUUUALRRQKYC0UUtAwooooELS0lLTGLS9aSlFIBRSgUClFMBQKcKaKcKYmPFSrUQqRaaETpVmLrVVTViM9K0iyWdp4f8A+QUn+8a1Ky/DrbtLX2Y1qVnP4mUtgoooqRhRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFJmjNAC0UUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAlFGBSYoA8TFFJmipGLRR2ooEGaSl70lABRS0nSmAtFA5oPJpAApaQelFAC0opKUUBYMUuKSloCwUUUUALRR0ooGFLRmigQUtIKKBjqM0ZopgLSjmkpRRcBaUUlLQIUU4U2nCi4x1OFMp4qkIetPFMWpFpgSLU8dQqKnSrRLOx8MnOmH/fNbFY3hj/kGt/10NbNZPdlBRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABSYpaKAExRS0UAJS0UUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABTS2D0NOooA8Q6UUmaWpAKXOKSgUDFpKDQKBMMYFHWiigYvTpRmkooAWiiimKwtFHWgUgFooozQAuaKSloAWikoFAxaKKKAFozRRQAooopaAClFJS0wFpaQUtADs0tNFOoAcKeKjFOFMRItSrUIqVKpAWEqZOagQ1PH1q0QzsPDS400+7mtisjw2c6af981r1m92WFFFFIAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACikozQAtFJmloAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigBKMe9LTS2OxoA8RpaSk61IMd2pKKKAA0fSl6UlABS0lLnNAwpaTNGaYrBS0lLSGFLRQKYhaKSlpDClpKUUAFFAoFABSikzS8UDFoxSUUAOopKWi4haWm0opjHUopBSg0ALThTacKAFFOFIKcKYhwqRajFSrTQiVanjNV1qdKtCOy8MMDp7DuHNbNYPhU/6JL/vVvVmxhRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAlGKWigBKKWigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKSjFAHiFFGaM1ABRRRTAKDRmigAHNFJiigB1FIOKCaBi0uaSigBaKKMc0CFpaTNGaAFopKWgYtFJRQMWikpRQIU0UmaWgYtLSUUALmlBpKUUALSim04UAOFLmm04UwHU4UwU4UxEq1ItRLUq1QiValSolNTJVITOs8Kf8e03+9W/WF4VXFnKcdXrdqGMKKKKQBRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFJQAtFJRQAtFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAU3cR2p1FAHh5o60lBqQFopO1FAC0neiigYtFJRQAvaijPFGaAFxRSZozQA6im9acKAuGM+tK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";

            var image = new Image();
            image.onload = drawNewImage;

            var RECORD_LEN = 20;
            var recordedImages = new Array(RECORD_LEN);
            var count = 0;

            function drawNewImage() {
                meContext.clearRect(0, 0, meContext.canvas.width, meContext.canvas.height);
                meContext.drawImage(image, 0, 0, meContext.canvas.width, meContext.canvas.height);

                setTimeout(nextImage, 10); // Simulates 100 frames per second
            }

            function drawOldImage() {
                var curImage = count % RECORD_LEN; // Cyclic loop over the array
                meContext.clearRect(0, 0, meContext.canvas.width, meContext.canvas.height);
                meContext.drawImage(recordedImages[curImage], 0, 0, meContext.canvas.width, meContext.canvas.height);

                setTimeout(nextImage, 10); // Simulates 100 frames per second
            }

            function nextImage() {
                count++;
                if (count <= 1000) // Phase I (during first 10 seconds): use live camera feed
                {
                    // Generating a random image src (Just for this example!!, instead of using the real camera feed)
                    var newImgSrc = chairImgSrc.slice(0, -11) + ("00000" + count).slice(-6) + "/2Q==";
                    // (CHROME MEMORY LEAK #1: editing the 'src' of an existing image with new bytes creates a new memory that never gets released)
                    image.src = newImgSrc;

                    // Cloning the image, to keep a recorded array of the last N frames
                    var $tmpImage = $(image);
                    // (CHROME MEMORY LEAK #2: clone() creates a new memory that never gets released
                    var clonedImage = $tmpImage.clone()[0];
                    recordedImages[count % RECORD_LEN] = clonedImage;
                }
                else                // Phase II: use recorded feed
                {
                    drawOldImage();
                }
            }

            window.onload = nextImage;
        </script>
    </body>
</html>

This example code takes a static image (of a chair) and modifies it randomly every frame (just to simulate my real camera feed).

For the first 1000 frames it shows the image, and stores the last 10 frames in a cyclic array, and from then on it just shows the 10 frames last recorded (in a loop).

(Obviously my real project is much more complicated, I just simplified it to illustrates the problem).

The question is - please suggest an alternative way (preferably - based on the provided source code) to perform the exact same functionality, without causing a memory leak in Chrome.

PS 1:

In chromium I found the following 2 related bugs, which were NOT really fixed (evidence - my code still leaks...):

  1. "manipulating img src via javascript will generate a massive memory leak" - https://code.google.com/p/chromium/issues/detail?id=36142
  2. "Memory usage grows infinitely when changing img.src" - https://code.google.com/p/chromium/issues/detail?id=114570

PS 2:

I'm fully aware of existing, similar questions in stackoverflow, and I made a lot of attempts, but none of them helped me solve my problem:

  1. Rapidly updating image with Data URI causes caching, memory leak
  2. Canvas even Img eating RAM and CPU
  3. Refresh image with a new one at the same url
  4. Setting img.src to dataUrl Leaks Memory
  5. Memory leak when loading images with javascript's settimeout

Some attempts I made, for example:

  • To make sure that the cache is not the cause, I work in Incognito mode of chrome, so cache is not relevant here.
  • Instead of setting bytes array as the src, I tried using blob URLs (but a similar leak still occurs):
    • img.src = window.URL.createObjectURL(new Blob([bytes.buffer], {type : "image/jpeg"}));
  • Tried putting the image in an iframe, and reloading it every X frames: this partially helps, but it's practically impossible for me to use this 'workaround'.

* UPDATE 29/Jan *

I replaced the following lines:

var $tmpImage = $(image);
var clonedImage = $tmpImage.clone()[0];

With:

var clonedImage = new Image();
clonedImage.src = newImgSrc;

and the leak is the same.

=> So I am down to 'only' 1 bug that requires a workaround (in 2 places): leak when editing an image's src.

like image 301
o_c Avatar asked Jan 23 '14 13:01

o_c


People also ask

Does Chrome cause memory leaks?

Google Chrome is one of the popular web browsers and Chrome memory leak is one of the common issues. Today we will talk about this problem on the MiniTool website. If you find there are many tabs of Chrome in Task Manager and Chrome uses much memory, follow these solutions below to easily fix the issue.

How does Chrome dev tools detect memory leaks?

Visualize memory consumption with the performance profiler​ The performance profiler in Chrome can visualize memory usage and graph it over time. To try this out, open the DevTools in Chrome and switch to the Performance tab. Note that we use an Incognito window when measuring performance.


1 Answers

I had the same problem. The only workaround I found was to reduce the number of new Image() to use (ideally one):

function ImageLoader() {
  var img = new Image();
  var queue = [];
  var lock = false;
  var lastURL;
  var lastLoadOk;
  return { load: load };

  function load(url, callback, errorCallback) {
    if (lock) return queue.push(arguments);
    lock = true;
    if (lastURL === url) return lastLoadOk ? onload() : onerror();
    lastURL = url;
    img.onload = onload;
    img.onerror = onerror;
    img.src = url;

    function onload() {
      lastLoadOk = true;
      callback(img);
      oncomplete();
    }
    function onerror() {
      lastLoadOk = false;
      if (errorCallback) errorCallback(url);
      oncomplete();
    }
  }
  function oncomplete() {
    lock = false;
    if (queue.length) load.apply(null, queue.shift());
  }
}
var loader = new ImageLoader();
loader.load(url1, function(img) { // do something });
loader.load(url2, function(img) { // do something });

Note that images will be loaded in serie. If if want to load 2 images in parallel, you'll need to instantiate 2 ImageLoader.

like image 69
gtournie Avatar answered Oct 05 '22 23:10

gtournie