2

I am trying to understand why memory continues to accumulate in Chrome (version 38.0.2125.111) when drawing images to a HTML5 Canvas. Using the below code, I watch the 'Memory' figure for my tab in Chrome's Task Manager increase by about 300-400kb per second up to anywhere between 35mb and 50mb before dropping right down to about 5mb. After that happens once, as the process continues the memory just keeps climbing and climbing (i.e. it nevers appears to be cleared again). If I click 'Go' again or even if I refresh the page the memory does not drop at all.

<!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>

This is a micro example of how my larger application runs. The user input triggers the animation to start and they generally run for a maximum of 5 seconds and then stop. The user then gives input again to start another animation. This can be repeated hundreds of times. As mine has more images I am finding the memory increasing at a rate of 3-4mb per second and before long I am hitting the Aw Snap error as the memory has gotten over 1.4gb. Am I doing something wrong? Is there any way I can force the 'clean up' process that the browser seems to apply just once more often?

Note that when I set my loop up using requestAnimationFrame instead of a timer, I find that the memory increase occurs even if I do not actually draw anything (i.e. I make no drawImage call).

JoriO
  • 1,050
  • 6
  • 13
rufus
  • 19
  • 4
  • I think you're right (ref. my now deleted answer), it's most likely a bug in the current version. You could answer this yourselves and mark it as the correct answer. –  Nov 07 '14 at 20:25

2 Answers2

0

You should use RAF, setInterval should actually be your last resort because it will hog the browser as it tries to keep the loop on time. Take a look here if that makes no sense.

Instead, if you can't use RAF, use setTimeout.

Note that when I set my loop up using requestAnimationFrame instead of a timer, I find that the memory increase occurs even if I do not actually draw anything (i.e. I make no drawImage call).

This is inevitable, because there's a function calling overhead (stack, parameters, etc.) each time RAF executes. But with RAF, GC should kick in at appropriate time (to avoid jerk) on most of today's browsers and clear staled old-generation data.

Community
  • 1
  • 1
nullpotent
  • 9,162
  • 1
  • 31
  • 42
  • Thanks for this. When I instead use RAF I see the exact same behaviour. It seems to clean up once when it first hits around 35mb of memory and thereafter it seems to simply accumulate more and more memory without ever cleaning up. – rufus Nov 06 '14 at 04:15
  • You are doing a serious amount of work there, and blitting canvas is an expensive operation. Hence it's a normal behavior. I'm intrigued. What happens when you draw your `img` directly? – nullpotent Nov 06 '14 at 04:17
  • It's the same result if I draw the image directly. I'm struggling to understand why when using RAF the memory increases so much and is not being cleared even if I make no DrawImage call at all within the loop (so all its really doing in that instance is looping through and changing the value of a few variables). – rufus Nov 06 '14 at 04:30
  • I explained that behavior, it's just a normal function call overhead. Memory accumulates because that's how GCs in browsers do. When it decides for the best moment to clear the memory, it will clear it. – nullpotent Nov 06 '14 at 04:34
  • Yep that makes sense. Does it makes sense though that after having done one memory cleanup after about 30 seconds of running within the first loop, that it would not do a single other memory clean in the next hour plus of time? During that time multiple loops have been instigated, the page has been refreshed, other tabs have been open and the tab in question has been left dormant for a period of time. The memory has not once been cleared and has now climbed to over 500mb. It really doesn't seem like the browser has found another convenient time to purge the old memory. – rufus Nov 06 '14 at 05:52
  • Also, from my testing this doesn't seem to occur on the latest version of Chrome Canary (i.e. Canary seems to continue to regularly purge the old memory so that the total memory routinely returns to the baseline level). – rufus Nov 06 '14 at 05:52
  • That indeed seems odd. So which chrome you were using? – nullpotent Nov 06 '14 at 06:12
  • Version 38.0.2125.111 m. Apprently that is the up to date version. – rufus Nov 06 '14 at 06:19
0

This does appear to be a potential bug with the current version of Chrome. I have raised an issue with Google in the hope of having this resolved.

Thanks for the assistance.

rufus
  • 19
  • 4