【问题标题】:Memory increase drawing to Canvas内存增加绘图到画布
【发布时间】:2024-04-18 05:35:01
【问题描述】:

我试图了解为什么在将图像绘制到 HTML5 画布时,内存会继续在 Chrome(版本 38.0.2125.111)中累积。使用下面的代码,我在 Chrome 的任务管理器中看到我的标签的“内存”数字以每秒约 300-400kb 的速度增长到 35mb 到 50mb 之间的任何地方,然后下降到大约 5mb。在那之后发生一次,随着过程的继续,记忆只会不断攀升和攀升(即它似乎永远不会再次被清除)。如果我再次单击“开始”,或者即使我刷新页面,内存也不会下降。

<!DOCTYPE HTML>
<html>
    <head>
        <script type="text/javascript">
            function tryit () {
                var px=1;
                var py=1;
                var canvas = document.getElementById('myCanvas');
                var context = canvas.getContext('2d');
                var canvas2 = document.getElementById('myCanvas2');
                var context2 = canvas2.getContext('2d');
                var img=document.getElementById("img1");
                var thereps=document.getElementById("txtreps").value;
                
                context2.drawImage(img,0,0);

                var counter=1;

                function loop() {
                    counter=counter+1;
                    px=Math.random()*1000;
                    py=Math.random()*800;
                    
                    context.drawImage(canvas2, 0, 0, 10, 16, px,py,10,16);
                    if (counter>=thereps) {
                        clearInterval(myTimer);
                        context.clearRect(0,0,1034,814);
                        alert("done");
                    }
                }
                myTimer = setInterval(loop,17);
            }
        </script>
    </head>
    <body>
        Loop: 
        <input id="txtreps" type="text" size="6" value="10000"/> 
        times 
        <input type="button" onclick="tryit();" value="Go"/>
        
        <div style="position:relative;width:1034px;height:814px;border:1px solid grey;">
            <canvas id="myCanvas" width="1034" height="814" style="visibility: visible; position: absolute; top:0; left: 0;border:1px solid black;" ></canvas>          
            <canvas id="myCanvas2" width="10" height="16" style="visibility: hidden;position:absolute; left:0px; top:0px;border:1px solid red;" ></canvas>
            <img id="img1" src="untitled.png" width="10" height="16" style="visibility: hidden; position: absolute; top:0; left: 0;border:1px solid green;">
        </div>
    </body>
</html>

这是我的大型应用程序如何运行的一个微型示例。用户输入触发动画开始,它们通常运行最多 5 秒然后停止。然后用户再次输入以开始另一个动画。这可以重复数百次。随着我的图像越来越多,我发现内存以每秒 3-4mb 的速度增加,不久我就遇到了 Aw Snap 错误,因为内存已经超过 1.4gb。难道我做错了什么?有什么方法可以强制执行浏览器似乎只经常应用一次的“清理”过程?

请注意,当我使用 requestAnimationFrame 而不是计时器设置循环时,我发现即使我实际上没有绘制任何东西(即我没有进行 drawImage 调用),内存也会增加。

【问题讨论】:

  • 我认为你是对的(参考我现在删除的答案),这很可能是当前版本中的一个错误。您可以自己回答并标记为正确答案。

标签: javascript html memory canvas


【解决方案1】:

你应该使用RAFsetInterval 实际上应该是你最后的手段,因为它会占用浏览器,因为它试图保持循环按时进行。 Take a look here if that makes no sense.

相反,如果您不能使用RAF,请使用setTimeout

请注意,当我使用 requestAnimationFrame 而不是 一个计时器,我发现即使我不这样做也会发生内存增加 实际绘制任何东西(即我没有调用 drawImage)。

这是不可避免的,因为每次RAF 执行时都会有函数调用开销(堆栈、参数等)。 但是对于RAFGC 应该在当今大多数浏览器上在适当的时间启动(以避免混蛋)并清除过时的old-generation 数据。

【讨论】:

  • 谢谢。当我改为使用 RAF 时,我看到了完全相同的行为。当它第一次达到大约 35mb 的内存时,它似乎会清理一次,然后它似乎只是在没有清理的情况下积累了越来越多的内存。
  • 你在那里做了大量的工作,并且 blitting canvas 是一项昂贵的操作。因此,这是一种正常的行为。我很感兴趣。当您直接绘制 img 时会发生什么?
  • 直接画图也是一样的结果。我很难理解为什么在使用 RAF 时内存会增加这么多并且即使我在循环中根本没有进行 DrawImage 调用也没有被清除(所以它在那个实例中真正做的就是循环并改变 a几个变量)。
  • 我解释了这种行为,它只是一个正常的函数调用开销。内存会累积,因为这就是浏览器中 GC 的做法。当它决定清除内存的最佳时机时,它会清除它。
  • 是的,这是有道理的。尽管在第一个循环中运行大约 30 秒后完成了一次内存清理之后,它不会在接下来的一小时内执行一次其他内存清理,这是否有意义?在此期间,已经引发了多个循环,页面已刷新,其他选项卡已打开,相关选项卡已休眠一段时间。内存从未被清除过,现在已经攀升到 500MB 以上。浏览器似乎真的没有找到另一个方便的时间来清除旧内存。
【解决方案2】:

这似乎是当前 Chrome 版本的潜在错误。我已向 Google 提出了一个问题,希望能得到解决。

感谢您的帮助。

【讨论】: