HTML5 getImageData 的 JavaScript 内存泄漏
我一直在努力为我正在创建的 JavaScript 游戏制作一些视觉效果,我注意到我用来调制精灵颜色的一段代码使我的浏览器内存使用量不断增加,看似没有限制。
您可以在此处查看代码和内存泄漏: http://timzook. tk/javascript/test.html
这种内存泄漏仅发生在我的 updateimage() 函数中,当我每帧从画布上下文中调用 getImageData (通过 setInterval)以便创建一个新的 ImageData 对象进行重新着色时。我本以为 javascript 的垃圾收集器会销毁旧的垃圾收集器,但如果不是的话,我不知道如何手动销毁它。任何帮助弄清楚为什么会这样做或如何解决它的帮助将不胜感激。
我的问题与此非常相似: 使用 getImageData、javascript、HTML5 canvas 会导致内存泄漏 但是,我需要我的代码运行 setInterval 调用的函数中的每一帧,他将其移到 setInterval 函数之外的解决方案对我来说不是一个选择,而且我不能留下评论询问他是否找到了解决它的其他方法。
测试人员请注意:由于此示例使用 getImageData,因此无法仅通过将其放入 .html 文件进行本地测试,因此需要 Web 服务器。而且它显然使用了 HTML5 元素,因此某些浏览器无法使用它。
编辑:*已解决*谢谢,下面的解决方案修复了它。我没有意识到您可以像在 drawImage() 中使用图像一样使用画布元素,我重组了我的代码,因此它现在使用的内存显着减少。如果有人想查看,我已将更改后的代码上传到上面链接的页面。
I've been working on trying to make some visual effects for a javascript game I'm creating, and I noticed a piece of code that I'm using to modulate the color of my sprites makes my browsers memory usage go up and up, seemingly without limit.
You can see the code and the memory leak here: http://timzook.tk/javascript/test.html
This memory leak only happens in my updateimage() function when I call getImageData from my canvas context every frame (via setInterval) in order to make a new ImageData object to recolor. I would have thought that javascript's garbage collector would be destroying the old one, but if not I have no idea how to destroy it manually. Any help figuring out why it does this or how to fix it would be appreciated.
My question is very similar to this one: What is leaking memory with this use of getImageData, javascript, HTML5 canvas However, I NEED my code to run every frame in the functioned called by setInterval, his solution of moving it outside the setInterval function isn't an option for me, and I can't leave a comment asking if he found some other method of solving it.
Note to people testing it out: Since this example uses getImageData, it can't be tested out locally just by throwing it in a .html file, a web server is required. Also it obviously uses HTML5 elements so some browsers won't work with it.
Edit: *SOLVED* Thanks, the solution below fixed it. I didn't realize that you could use a canvas element the same way as you could use an image in drawImage(), I restructured my code so it now uses significantly less memory. I uploaded this changed code to the page linked above, if anyone wants to see it.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您不会因调用
getImageData()
而发生内存泄漏。问题的根源在于这一行:TempImg.src = ImgCanvas.toDataURL("image/png");
实际上,每次执行该行代码时,浏览器都会“下载”另一个图像并存储记忆中的它。因此,您最终得到的实际上是一个增长非常快的缓存。您可以通过在 Chrome 中打开网站并检查开发人员工具的资源选项卡 (
ctrl+shift+i
) 来轻松验证这一点。您可以通过创建
TempImgCanvas
并将图像数据存储在该画布上来解决此问题,而不是在每次调用updateimage()
循环后保持图像对象更新。我必须离开一段时间,但如果您愿意,我可以在回来后几个小时内编写一个示例。
编辑:我对内容进行了一些重组并消除了您的缓存问题。您只需要做两处更改。第一个是将
updateimage()
函数替换为以下函数:第二个是将
draw()
中的最后一行更新为如下所示:drawImg(ImgCanvas, Positions[i].x, Positions[i].y, Positions[i].x+Positions[i].y);
使用此更新后的代码,我们只需引用原始基础(白色)图像数据并根据每个计算新值现在我们将执行
updateimage()
函数。当您调用getImageData()
时,您会收到画布上图像数据的副本,因此,如果您编辑画布或数据,另一个保持不变。您一开始就已经获取了原始基础图像数据,因此只需使用它就有意义,而不必在每次更新时重新获取它。另外,您会注意到我修改了循环,稍微改变了图像颜色。通过获取要访问/修改的实际数据数组的句柄,您就不必在每次循环时从父对象解析数组位置。这项技术实际上带来了相当不错的性能提升。你的表现一开始就很好,但提高效率也没什么坏处,因为它非常简单。
You aren't getting a memory leak from your calls to
getImageData()
. The source of your problem is this line:TempImg.src = ImgCanvas.toDataURL("image/png");
Effectively, every time that line of code is executed the browser "downloads" another image and stores it in memory. So, what you actually end up with is a cache that is growing very quickly. You can easily verify this by opening the site in Chrome and checking the resources tab of the developer tools (
ctrl+shift+i
).You can work around this by making a
TempImgCanvas
and storing your image data on that canvas instead of keeping an image object updated after every call to yourupdateimage()
loop.I have to step away for a while, but I can work up an example in a few hours when I get back, if you would like.
Edit: I restructured things a bit and eliminated your caching issue. You just have to make two changes. The first is replacing your
updateimage()
function with this one:The second is updating the last line in
draw()
to read as follows:drawImg(ImgCanvas, Positions[i].x, Positions[i].y, Positions[i].x+Positions[i].y);
Using this updated code, we simply refer to the original base (white) image data and calculate new values based on that every time we go through the
updateimage()
function. When you callgetImageData()
you receive a copy of the image data on the canvas, so if you edit the canvas or the data, the other one remains untouched. You were already grabbing the original base image data to begin with, so it made sense to just use that instead of having to re-acquire it every time we updated.Also, you'll notice that I modified your loop that changes the image color slightly. By obtaining a handle to the actual data array that you want to access/modify, you save yourself having to resolve the array location from the parent object every time you go through the loop. This technique actually results in a pretty nice performance boost. Your performance was fine to start with, but it can't hurt to be more efficient since it's pretty straight-forward.