CreateJS / EaselJS

The Easel Javascript library provides a full, hierarchical display list, a core interaction model, and helper classes to make working with the HTML5 Canvas element much easier.
http://createjs.com/
MIT License
8.14k stars 1.97k forks source link

Patch to memory leak on some Android 4 devices #305

Closed ghost closed 11 years ago

ghost commented 11 years ago

Hello.

Some Japanese users found the problem of memory leak on some Android 4 devices popular in Japan which crashes the default browser just after few frames of the beginning of the Canvas animation. This is the list of the devices in question.

I did a little test to avoid it as mentioned in some Japanese blog. At first here is the test code. This code crashes the default browser.

<html>
<head>
<meta charset="UTF-8">
<title>sample</title>
<script src="easeljs-0.6.0.min.js"></script>
<script>
    var canvas, stage, circle, speedX = 5, speedY = 3, radius = 15;

    function init() {
        canvas = document.getElementById("canvas");
        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;
        stage = new createjs.Stage(canvas);

        circle = new createjs.Shape();
        var g = circle.graphics;
        g.beginFill(createjs.Graphics.getRGB(255, 0, 0, 1));
        g.drawCircle(0, 0, radius);
        stage.addChild(circle);
        circle.x = canvas.width/2;
        circle.y = canvas.height/2;

        createjs.Ticker.useRAF = true;
        createjs.Ticker.setFPS(30);
        createjs.Ticker.addEventListener("tick", tick);
    }

    function tick() {
        circle.x += speedX;
        circle.y += speedY;
        if(circle.x - radius < 0 || circle.x + radius > stage.canvas.width) { speedX *= -1;  }
        if(circle.y - radius < 0 || circle.y + radius > stage.canvas.height) { speedY *= -1; }

        stage.update();
    }
    </script>
</head>
<body onload="init()">
<canvas id="canvas" style="background-color: #DDDDDD"></canvas>
</body>
</html>

And these two are the solution. We make some change in p.clear method of easeljs/display/Stage.js.

p.clear = function() {
    if (!this.canvas) { return; }
    var ctx = this.canvas.getContext("2d");
    ctx.setTransform(1, 0, 0, 1, 0, 0);
    var m = (this.canvas.width + 255) >> 8;
    var n = (this.canvas.height + 255) >> 8;
    for (var i = 0; i < m; ++i) {
        for (var j = 0; j < n; ++j) {
            ctx.clearRect(i << 8, j << 8, 256, 256);
        }
    }
}
p.clear = function() {
    if (!this.canvas) { return; }
    var ctx = this.canvas.getContext("2d");
    ctx.setTransform(1, 0, 0, 1, 0, 0);
    ctx.clearRect(0, 0, this.canvas.width + 1, this.canvas.height + 1);
}

Both methods can solve the problem.

Sorry for my poor English.

gskinner commented 11 years ago

Sorry for the delayed response. To be clear - just adding the +1 is fixing the memory issue for you? That's quite interesting. If so, we can definitely implement that here, and in other places where we clear canvases.

If you are aware of any information on why this fixes the problem, I'd love to see it, just to ensure we fix it properly.

lannymcnie commented 11 years ago

The NEXT version of EaselJS has been pushed to GitHub, and includes the +1 workaround on ALL clearRect usages.

ghost commented 11 years ago

to Mr. gskinner, Mr. lannymcnie I'm sorry to replay so late. I'm not sure why this +1 can avoid the problem and no japanese blog mention about it. The NEXT version will be helpful for Japanese CreateJS user. Thank you very much.