Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/465.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/html/91.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript Safari中的数据URI泄漏(was:HTML5画布内存泄漏)_Javascript_Html_Canvas_Safari_Websocket - Fatal编程技术网

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

Javascript Safari中的数据URI泄漏(was:HTML5画布内存泄漏),javascript,html,canvas,safari,websocket,Javascript,Html,Canvas,Safari,Websocket,我创建了一个网页,通过Websocket接收base64编码的位图,然后将它们绘制到画布上。它工作得很好。除此之外,浏览器(无论是Firefox、Chrome还是Safari)的内存使用量都会随着每个图像的增加而增加,而且不会下降。所以,我的代码中一定有内存泄漏或其他错误。如果我注释掉对context.drawImage的调用,则不会发生内存泄漏(当然,该图像永远不会被绘制)。下面是我的网页中的片段。感谢您的帮助。谢谢 // global variables var canvas; var co

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

// 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>
这与以下站点上描述的问题相同:


更新12/21/2011

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


更新日期:2012年3月1日


好的,我最终通过使用atob()对base64编码的数据URI字符串进行解码,然后创建一个像素数据数组,并使用putImageData将其写入画布来解决这个问题(请参阅)。这样做(与不断修改图像的“src”和在onload函数中调用drawImage相反),我不再在Safari或任何浏览器中看到内存泄漏

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

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

如果你一次又一次地发送相同的图像,你每次都在制作一个新图像。这很糟糕。您可能希望执行以下操作:

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代码,而不是检查图像是否已经完成)。不过,我将把这些部分留给你,你会明白的。

这很有趣。这是值得向不同的浏览器供应商报告的一个bug(我觉得这不应该发生)。你的回答可能是“不要那样做,而是那样做”,但至少你会知道正确的答案,并且在博客上写一篇有趣的文章(肯定会有更多的人遇到这个问题)

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

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


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

我不相信这是一个bug。问题似乎是图像堆叠在一起。因此,要清除内存,需要使用clearRect()在画布中绘制新图像之前清除画布

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


如果在绘制图像之前添加clearRect调用,或者使用重置技巧将宽度设置为自身,会发生什么情况?(from)我尝试了context.clearRect(0,0,canvas.width,canvas.height);在drawImage之前,但内存泄漏仍然发生。您确定它不仅仅是存储图像,以防您返回页面,以便它可以从内存加载图像吗?可能是运行时优化。2018年:Safari v11-->数据uri仍然疯狂地泄漏(“我会注意到把它放在prod中”有点疯狂)。Firefox Quantum-->有点泄漏。Chrome-->完全可以。如果每个图像都是唯一的,并且随着您创建每个新的HTMLImageElement(
new image()
),内存使用量会增加,这很正常!那么,如果我注释掉对drawImage的调用,为什么内存使用率会保持不变呢?现在,在您的代码中,每次调用
drawImage
,都会调用
new Image()
。除非您只调用
drawImage
X次,其中X是唯一图像的数量,否则您会遇到一个巨大的问题,因为您正在生成比您想要的更多的
new Image()
s。有多少个图像,调用了多少次
new Image()
?有无限多个唯一的图像,我的Websocket服务器想要发送多少。我的观点是,当我放弃调用drawImage(通过注释掉它)时,new Image()分配的内存似乎在一段时间后被释放,可能是通过垃圾收集。但是当我在呼叫drawImage中离开时,记忆永远不会被释放。啊,我明白了。为了好玩,试着注释掉
drawImage
调用,并用
context.fillRect(0,0,50,50)
调用替换它。它还漏吗?我注意到由于某种原因,在我的情况下画布的高度似乎是错误的。在代码示例中,使用图像高度作为“canvas.height”似乎可以做到这一点。
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
    }
}