Dav*_*dia 25 javascript html5 memory-leaks data-uri html5-canvas
我有一个网页,可以快速从服务器流式传输JSON并显示其中的一些内容,大约10次/秒.一部分是base64编码的PNG图像.我发现了几种不同的显示图像的方法,但是所有这些方法都会导致无限的内存使用.它在几分钟内从50mb上升到2gb.适用于Chrome,Safari和Firefox.没试过IE.
我首先通过查看Activity Monitor.app发现了内存使用情况 - Google Chrome渲染器进程不断地占用内存.然后,我看着Chrome的资源检查器(View
> Developer
> Developer Tools
,Resources
),我看到它被缓存的图像.每次我更改img src
,或创建一个新的Image()并设置它src
,Chrome缓存它.我只能想象其他浏览器也在做同样的事情.
有没有办法控制这个缓存?我可以把它关掉,或做鬼鬼祟祟的事情,这样就不会发生吗?
编辑:我希望能够在Safari/Mobile Safari中使用该技术.此外,如果有人有任何想法,我会对其他快速刷新图像的方法持开放态度.
这是我尝试过的方法.每个驻留在一个在AJAX完成时调用的函数.
src
在img
标记上设置属性快速.显示得很好.泄漏就像疯了似的.
$('#placeholder_img').attr('src', 'data:image/png;base64,' + imgString);
Run Code Online (Sandbox Code Playgroud)
img
用a 替换canvas
,并使用drawImage
显示正常,但仍然泄漏.
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;
Run Code Online (Sandbox Code Playgroud)
canvas
内容我在这里做错了 - 图像显示小而且看起来像随机噪音.此方法使用受控量的内存(增长到100mb并停止),但速度很慢,尤其是在Safari中(那里的CPU使用率约为50%,Chrome中为17%).这个想法来自于类似的SO问题:Safari中的数据URI泄漏(是:使用HTML5画布的内存泄漏)
var img = atob(imgString);
var binimg = [];
for(var i = 0; i < 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 < len; i++) {
imgdata.data[i-8] = bytearray[i];
}
// Write it back
ctx.putImageData(imgdata, 0, 0);
Run Code Online (Sandbox Code Playgroud)
小智 5
我知道这个问题发布已经有好几年了,但该问题在最新版本的 Safari 浏览器中仍然存在。因此,我有一个适用于所有浏览器的明确解决方案,我认为这可以挽救工作或生命!
将以下代码复制到 html 页面中的某处:
// Methods to address the memory leaks problems in Safari
var BASE64_MARKER = ';base64,';
var temporaryImage;
var objectURL = window.URL || window.webkitURL;
function convertDataURIToBlob(dataURI) {
// Validate input data
if(!dataURI) return;
// Convert image (in base64) to binary data
var base64Index = dataURI.indexOf(BASE64_MARKER) + BASE64_MARKER.length;
var base64 = dataURI.substring(base64Index);
var raw = window.atob(base64);
var rawLength = raw.length;
var array = new Uint8Array(new ArrayBuffer(rawLength));
for(i = 0; i < rawLength; i++) {
array[i] = raw.charCodeAt(i);
}
// Create and return a new blob object using binary data
return new Blob([array], {type: "image/jpeg"});
}
Run Code Online (Sandbox Code Playgroud)
base64Image
然后,当您收到Base64 格式的新帧/图像(例如data:image/jpeg;base64, LzlqLzRBQ...
)并且想要更新 html<img />
对象imageElement
时,请使用以下代码:
// Destroy old image
if(temporaryImage) objectURL.revokeObjectURL(temporaryImage);
// Create a new image from binary data
var imageDataBlob = convertDataURIToBlob(base64Image);
// Create a new object URL object
temporaryImage = objectURL.createObjectURL(imageDataBlob);
// Set the new image
imageElement.src = temporaryImage;
Run Code Online (Sandbox Code Playgroud)
根据需要重复最后的代码,不会出现内存泄漏。此解决方案不需要使用 canvas 元素,但您可以调整代码以使其工作。
我认为对于数据 URL 的内存使用情况没有任何保证。如果您能找到一种方法让它们在一个浏览器中运行,那么它对其他浏览器或版本的影响几乎没有任何保证。
如果将图像数据放入 blob 中,然后创建 blob URL,则可以释放该数据。
下面是一个将数据 URI 转换为 blob URL 的示例;您可能需要在 Chrome 以及未来版本的 Chrome 以外的浏览器上更改/删除webkit-
&前缀。WebKit-
var parts = dataURL.match(/data:([^;]*)(;base64)?,([0-9A-Za-z+/]+)/);
//assume base64 encoding
var binStr = atob(parts[3]);
//might be able to replace the following lines with just
// var view = new Uint8Array(binStr);
//haven't tested.
//convert to binary in ArrayBuffer
var buf = new ArrayBuffer(binStr.length);
var view = new Uint8Array(buf);
for(var i = 0; i < view.length; i++)
view[i] = binStr.charCodeAt(i);
//end of the possibly unnecessary lines
var builder = new WebKitBlobBuilder();
builder.append(buf);
//create blob with mime type, create URL for it
var URL = webkitURL.createObjectURL(builder.getBlob(parts[1]))
return URL;
Run Code Online (Sandbox Code Playgroud)
解除分配就像这样简单:
webkitURL.revokeObjectURL(URL);
Run Code Online (Sandbox Code Playgroud)
您可以使用您的 blob URL 作为您img
的src
.
不幸的是,v10 之前的 IE 似乎不支持 blob URL。
http://www.w3.org/TR/FileAPI/#dfn-createObjectURL
http://www.w3.org/TR/FileAPI/#dfn-revokeObjectURL
http://caniuse.com/#search=blob%20url
归档时间: |
|
查看次数: |
11806 次 |
最近记录: |