Data URI leak in Safari (was: Memory Leak with HTML5 canvas)

前端 未结 4 2035
盖世英雄少女心
盖世英雄少女心 2020-12-08 16:11

I have created a webpage that receives base64 encoded bitmaps over a Websocket and then draws them to a canvas. It works perfectly. Except, the browser\'s (whether Firefox

相关标签:
4条回答
  • 2020-12-08 16:40

    you're probably drawing the image a lot more times than you are expecting to. try adding a counter and output the number to an alert or to a div in the page to see how many times the image is being drawn.

    0 讨论(0)
  • 2020-12-08 16:43

    I don't believe this is a bug. The problem seems to be that the images are stacked on top of each other. So to clear up the memory, you need to use clearRect() to clear your canvas before drawing the new image in it.

    ctx.clearRect(0, 0, canvas.width, canvas.height);

    How to clear your canvas matters

    0 讨论(0)
  • 2020-12-08 16:44

    That's very interesting. This is worth reporting as a bug to the various browser vendors (my feeling is that it shouldn't happen). You might responses along the lines of "Don't do that, instead do such and such" but at least then you'll know the right answer and have an interesting thing to write up for a blog post (more people will definitely run into this issue).

    One thing to try is unsetting the image src (and onload handler) right after the call to drawImage. It might not free up all the memory but it might get most of it back.

    If that doesn't work, you could always create a pool of image objects and re-use them once they have drawn to the canvas. That's a hassle because you'll have to track the state of those objects and also set your pool to an appropriate size (or make it grow/shrink based on traffic).

    Please report back your results. I'm very interested because I use a similar technique for one of the tightPNG encoding in noVNC (and I'm sure others will be interested too).

    0 讨论(0)
  • 2020-12-08 16:47

    Without actual working code we can only speculate as to why.

    If you're sending the same image over and over you're making a new image every time. This is bad. You'd want to do something like this:

    var images = {}; // a map of all the images
    
    ws.onmessage = function(evt)
    {
        var received_msg = evt.data;
        var display_image;
        var src = 'data:image/bmp;base64,'+received_msg;
        // We've got two distinct scenarios here for images coming over the line:
        if (images[src] !== undefined) {
          // Image has come over before and therefore already been created,
          // so don't make a new one!
          display_image = images[src];
          display_image.onload = function () {
              context.drawImage(this, 0, 0);
          }
        } else {
          // Never before seen image, make a new Image()
          display_image = new Image();
          display_image.onload = function () {
              context.drawImage(this, 0, 0);
          }
          display_image.src = src;
          images[src] = display_image; // save it for reuse
        }
    }
    

    There are more efficient ways to write that (I'm duplicating onload code for instance, and I am not checking to see if an image is already complete). I'll leave those parts up to you though, you get the idea.

    0 讨论(0)
提交回复
热议问题