Javascript 将img.src设置为dataUrl会泄漏内存
下面我创建了一个简单的测试用例,它显示了当img标记的src设置为不同的dataurl时,它会泄漏内存。在src被更改为其他内容之后,似乎从未卸载图像数据Javascript 将img.src设置为dataUrl会泄漏内存,javascript,html,dom,canvas,memory-leaks,Javascript,Html,Dom,Canvas,Memory Leaks,下面我创建了一个简单的测试用例,它显示了当img标记的src设置为不同的dataurl时,它会泄漏内存。在src被更改为其他内容之后,似乎从未卸载图像数据 <!DOCTYPE html> <html> <head> <title>Leak Test</title> <script type="text/javascript"> canvas = null; context = nu
<!DOCTYPE html>
<html>
<head>
<title>Leak Test</title>
<script type="text/javascript">
canvas = null;
context = null;
image = null;
onLoad = function(event)
{
canvas = document.getElementById('canvas');
context = canvas.getContext('2d');
image = document.getElementById('image');
setTimeout(processImage, 1000);
}
processImage = function(event)
{
var imageData = null;
for (var i = 0; i < 500; i ++)
{
context.fillStyle = "rgba(" + Math.floor(Math.random() * 256) + "," + Math.floor(Math.random() * 256) + "," + Math.floor(Math.random() * 256) + "," + Math.random() +")";
context.fillRect(0, 0, canvas.width, canvas.height);
imageData = canvas.toDataURL("image/jpeg", .5);
image.src = imageData;
}
setTimeout(processImage, 1000);
}
</script>
</head>
<body onload="onLoad(event)">
<canvas id="canvas"></canvas>
<img id="image"></img>
</body>
</html>
泄漏试验
canvas=null;
上下文=空;
image=null;
onLoad=函数(事件)
{
canvas=document.getElementById('canvas');
context=canvas.getContext('2d');
image=document.getElementById('image');
setTimeout(processImage,1000);
}
processImage=函数(事件)
{
var-imageData=null;
对于(变量i=0;i<500;i++)
{
context.fillStyle=“rgba(“+Math.floor(Math.random()*256)+”,“+Math.floor(Math.random()*256)+”,“+Math.floor(Math.random()*256)+”,“+Math.random()+”);
context.fillRect(0,0,canvas.width,canvas.height);
imageData=canvas.toDataURL(“image/jpeg”,.5);
image.src=图像数据;
}
setTimeout(processImage,1000);
}
如果加载此html页面,RAM的使用会随着时间的推移而增加,并且永远不会被清除。此问题看起来非常类似:。我能做些什么来防止内存泄漏吗 我最后为这个问题做了一个变通。内存膨胀只有在image.src被更改时才会发生,所以我完全绕过了image对象。我通过获取dataUrl,将其转换为二进制文件(),然后使用jpg.js()解析它来实现这一点。使用jpg.js,我可以将图像复制回我的画布,因此图像元素完全是Bybased的,因此无需设置其src属性。我也遇到了这个问题,我确信这是一个浏览器错误。我在FF和Chrome中也看到了这种情况。至少Chrome曾经有一个类似的bug被修复了。我认为它还没有消失或者还没有完全消失。当我将img.src反复设置为唯一图像时,我看到内存不断增加。我用铬做了一个bug,如果你想增加一些重量:) (错误触发示例并不一定每次都会生成一个新的唯一图像,但至少很有可能会生成新的唯一图像)在Safari中为我解决了这个问题 此解决方法通过绕过泄漏的
图像
对象来避免内存增加
// 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"});
}
其他答案中未提及的一些解决方案: 用于浏览器 与@PaulMilham提到的类似,但具有附加功能和更好的API(imo) 用于NodeJS/Electron 用于NodeJS的通用图像处理库,具有读取和写入jpeg、png等图像(作为文件或仅在内存中)的功能
由于我的程序使用的是Electron,我最终使用了jpeg js,因为
jpeg js
提到它是一种性能更高的替代方案(因为它的核心是用本机代码编写的)。在处理图像后将源代码设置为固定的最小数据URI似乎可以解决我的问题:
const dummyPng = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAC0lEQVQYV2NgAAIAAAUAAarVyFEAAAAASUVORK5CYII=';
img.onload = () => {
// ... process the image
URL.revokeObjectURL(img.src);
img.onload = null;
img.src = dummyPng;
};
img.src = URL.createObjectURL(new window.Blob([new Uint8Array(data)], {type: 'image/png'}));
这是什么浏览器?您可以检查是否存在问题。GC是由浏览器内部处理的,因此您唯一能做的就是重写逻辑。这在Chrome和Firefox上都会发生,所以我假设这是根据规范或其他规定进行的。他们是否修复了错误?您可以在上查看错误状态。看起来它被标记为已修复。顺便说一句,WebKit(例如Safari和iOS上的Safari)也有内存泄漏的报告:这是问题的主要原因。谢谢还要注意的是,我可以使用javascript解决这个bug,但这并不理想,因为它需要比让浏览器处理更多的CPU。很酷,谢谢。我注意到了你的解决方案。这很好,也很有创意:)这些解决方法今天可以实现,这很酷,但我们在显示图像这样简单的事情上失败了,这仍然是一件很遗憾的事。你有什么样的代码可以告诉我吗?我正试图实现您所描述的东西,显然我不能很好地使用jpg.js。@JayhawksFan93请看。如果您的图像是jpeg格式,则只需使用开关的jpeg部分使用
decodeImage
方法。我遇到了类似的情况。我在画布上反复使用drawImage
来显示视频。我注意到记忆马上开始上升。我注意到你的作品中有canvas
标签。这是在canvas上工作还是在实际元素中工作?我应该注意,它会立即上升,几分钟后崩溃。内存在1gb到1.5gb之间。我从未尝试过使用canvas 2d在画布上绘制视频,但它似乎相当普遍,所以如果它泄漏,我会感到惊讶。你能粘贴复制问题的代码吗?
const dummyPng = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAC0lEQVQYV2NgAAIAAAUAAarVyFEAAAAASUVORK5CYII=';
img.onload = () => {
// ... process the image
URL.revokeObjectURL(img.src);
img.onload = null;
img.src = dummyPng;
};
img.src = URL.createObjectURL(new window.Blob([new Uint8Array(data)], {type: 'image/png'}));