首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Safari中的数据URI泄漏(was:使用HTML5画布的内存泄漏)

Safari中的数据URI泄漏(was:使用HTML5画布的内存泄漏)
EN

Stack Overflow用户
提问于 2011-12-16 19:04:27
回答 4查看 5.1K关注 0票数 18

我创建了一个网页,通过Websocket接收base64编码的位图,然后将它们绘制到画布上。它工作得很完美。不过,浏览器(无论是Firefox、Chrome还是Safari)的内存使用量随着图像的增加而增加,永远不会下降。所以,我的代码中肯定有内存泄漏或者其他错误。如果我注释掉对context.drawImage的调用,内存泄漏就不会发生(当然,图像永远不会被绘制)。下面是我网页上的片段。任何帮助都是非常感谢的。谢谢!

代码语言:javascript
复制
// global variables
var canvas;
var context;

...

ws.onmessage = function(evt)
{
    var received_msg = evt.data;
    var display_image = new Image();
    display_image.onload = function ()
    {
        context.drawImage(this, 0, 0);
    }
    display_image.src = 'data:image/bmp;base64,'+received_msg;
}

...

canvas=document.getElementById('ImageCanvas');
context=canvas.getContext('2d');

...

<canvas id="ImageCanvas" width="430" height="330"></canvas>

2011年更新12/19

我可以通过使用createElement/appendChild和removeChild动态创建/销毁画布大约每100个图像来解决这个问题。在那之后,我的Firefox和Chrome不再有内存问题了。

然而,Safari仍然存在内存使用问题,但我认为这是另一个问题,与画布无关。在Safari中反复更改映像的"src“似乎存在一个问题,似乎它永远不会释放这个内存。

代码语言:javascript
复制
display_image.src = 'data:image/bmp;base64,'+received_msg;  

这是在以下站点上描述的相同问题:http://waldheinz.de/2010/06/webkit-leaks-data-uris/

2011年更新12/21

我希望通过将接收到的base64字符串转换为blob (使用在这个站点上找到的"dataURItoBlob“函数)并返回到带有window.URL.createObjectURL的URL,将图像src设置为该URL,然后调用window.URL.revokeObjectURL来释放内存,从而解决Safari的问题。我把这一切都做好了,Chrome和Firefox正确地显示了图像。不幸的是,Safari似乎不支持BlobBuilder,所以我不能使用它。这很奇怪,因为包括O‘’Reilly“编程HTML5应用程序”在内的许多地方都表示BlobBuilder在Safari/中是受支持的。我从http://nightly.webkit.org/下载了最新的Windows夜间构建,并运行了WebKit.exe,但BlobBuilder和WebKitBlobBuilder仍未定义。

更新01/03/2012

好的,我最终通过用atob()解码base64 64编码的数据URI字符串,然后创建一个像素数据数组并使用putImageData将其写入画布(参见http://beej.us/blog/2010/02/html5s-canvas-part-ii-pixel-manipulation/)来修复这个问题。这样做(相对于经常修改图像的"src“和在onload函数中调用drawImage ),我不再在Safari或任何浏览器中看到内存泄漏。

EN

回答 4

Stack Overflow用户

发布于 2011-12-16 19:23:24

如果没有实际的工作代码,我们只能猜测原因。

如果你一遍又一遍地发送相同的图像,那么你每次都要做一个新的图像。这很糟糕。你会想做这样的事:

代码语言:javascript
复制
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
    }
}

有更有效的方法来编写(例如,我正在复制onload代码,并且我没有检查图像是否已经完成)。我会让你来决定的,你知道的。

票数 3
EN

Stack Overflow用户

发布于 2011-12-16 19:08:35

你可能比你预期的要多绘制图像。尝试添加一个计数器,并将该数字输出到警报或页面中的div,以查看正在绘制图像的次数。

票数 0
EN

Stack Overflow用户

发布于 2011-12-16 20:59:11

这非常有趣。这是值得向各种浏览器供应商报告的错误(我觉得这是不应该发生的)。你的回答可能是“不要这样做,而应该这样做”,但至少这样你会知道正确的答案,并有一件有趣的事情来写博客文章(更多的人肯定会遇到这个问题)。

要尝试的一件事是在调用drawImage之后立即取消对映像src (和onload处理程序)的设置。它可能不会释放所有的内存,但它可能会得到它的大部分。

如果这样做不起作用,您可以始终创建一个图像对象池,并在它们绘制到画布上之后再使用它们。这很麻烦,因为您必须跟踪这些对象的状态,并将您的池设置为适当的大小(或者根据流量使其增长/缩小)。

请报告你的结果。我非常感兴趣,因为我对noVNC中的一种noVNC编码使用了类似的技术(我相信其他人也会感兴趣)。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/8538917

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档