title: Rapidly updating image with Data URI causes caching, memory leak
body: <p>I have a webpage that rapidly streams JSON from the server and displays bits of it, about 10 times/second. One part is a base64-encoded PNG image. I've found a few different ways to display the image, but all of them cause unbounded memory usage. It rises from 50mb to 2gb within minutes. Happens with Chrome, Safari, and Firefox. Haven't tried IE.</p>
  
  <p>I discovered the memory usage first by looking at Activity Monitor.app -- the Google Chrome Renderer process continuously eats memory. Then, I looked at Chrome's Resource inspector (<code>View</code> > <code>Developer</code> > <code>Developer Tools</code>, <code>Resources</code>), and I saw that it was <strong>caching the images</strong>. Every time I changed the <code>img src</code>, or created a new Image() and set its <code>src</code>, Chrome cached it. I can only imagine the other browsers are doing the same.</p>
  
  <p>Is there any way to control this caching? Can I turn it off, or do something sneaky so it never happens?</p>
  
  <p>Edit: I'd like to be able to use the technique in Safari/Mobile Safari. Also, I'm open to other methods of rapidly refreshing an image if anyone has any ideas.</p>
  
  <p>Here are the methods I've tried. Each one resides in a function that gets called on AJAX completion.</p>
  
  <h1>Method 1 - Directly set the <code>src</code> attribute on an <code>img</code> tag</h1>
  
  <p>Fast. Displays nicely. Leaks like crazy.</p>
  
  <pre><code>$('#placeholder_img').attr('src', 'data:image/png;base64,' + imgString);
  </code></pre>
  
  <h1>Method 2 - Replace <code>img</code> with a <code>canvas</code>, and use <code>drawImage</code></h1>
  
  <p>Displays fine, but still leaks.</p>
  
  <pre><code>var canvas = document.getElementById("placeholder_canvas");
  var ctx = canvas.getContext("2d");
  var img = new Image();
  img.onload = function() {
      ctx.drawImage(img, 0, 0); 
  }   
  img.src = "data:image/png;base64," + imgString;
  </code></pre>
  
  <h1>Method 3 - Convert to binary and replace <code>canvas</code> contents</h1>
  
  <p>I'm doing something wrong here -- the images display small and look like random noise. This method uses a controlled amount of memory (grows to 100mb and stops), but it is slow, especially in Safari (~50% CPU usage there, 17% in Chrome). The idea came from this similar SO question: <a href="https://stackoverflow.com/questions/8538917/data-uri-leak-in-safari-was-memory-leak-with-html5-canvas">Data URI leak in Safari (was: Memory Leak with HTML5 canvas)</a></p>
  
  <pre><code>var img = atob(imgString);
  var binimg = [];
  for(var i = 0; i &lt; img.length; i++) {
      binimg.push(img.charCodeAt(i));
  }
  var bytearray = new Uint8Array(binimg);
  
  // Grab the existing image from canvas
  var ctx = document.getElementById("placeholder_canvas").getContext("2d");
  var width = ctx.canvas.width, 
      height = ctx.canvas.height;
  var imgdata = ctx.getImageData(0, 0, width, height);
  
  // Overwrite it with new data
  for(var i = 8, len = imgdata.data.length; i &lt; len; i++) {
      imgdata.data[i-8] = bytearray[i];
  }
  
  // Write it back
  ctx.putImageData(imgdata, 0, 0);
  </code></pre>