Reputation: 218
In the trivial case of creating and then destroying an instance of Phaser.Game there appears to be a memory leak. Below is a complete working example: click the button to create an instance, click again to destroy it. Repeatedly clicking the button causes memory usage to grow without bound. Is there something I'm missing about the phaser lifecycle that I should be doing instead?
I'm posting this as a code snippet rather than a jsfiddle because you need to look a a memory profiler or something like that to see the problem and so jsfiddle just complicates the matter.
<!doctype html>
<html>
<head>
<meta charset="UTF-8"/>
<title>test</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/phaser-ce/2.8.1/phaser.js">
</script>
</head>
<body>
<button id="button">Click</button>
<div id="canvas"></div>
<script>
window.onload = function() {
var d, n, game;
d = document.getElementById('button');
n = document.getElementById('canvas');
function preload() {
}
function create() {
}
function update() {
}
function handler() {
if(game) {
game.destroy();
game = null;
} else {
game = new Phaser.Game(800, 600, Phaser.AUTO, n, {
preload: preload,
create: create,
update: update
});
}
}
d.onclick = handler;
};
</script>
</body>
</html>
Upvotes: 1
Views: 1345
Reputation: 218
Answering (at least partially) my own question, the problem is in Phaser.CanvasPool. Whenever a new Phaser instance is created a new canvas is created and added to the pool. Destroying the instance dows not remove the canvas from the pool or mark it as available for re-use.
You can kinda-sorta hack this into working by doing something crude like setting Phaser.CanvasPool.pool = [] after calling game.destroy(), but that won't work if you have multiple phaser instances going.
If anyone knows what the correct workflow is supposed to be I'd love to know---Phaser.CanvasPool is one of phaser's points of contact with PIXI and all of those appear to be poorly documented.
EDIT: Found the source of the memory leak. It's Phaser.Utils.Debug.boot(), which adds a new canvas to the pool every time it's called, which by default is every time a phaser instance is created and booted.
The problem affects only WebGL-rendered canvases when enableDebug is enabled (which is the default).
For completeness, here's an edited version of the code above which disables debugging and therefore does not exhibit the memory leak:
<!doctype html>
<html>
<head>
<meta charset="UTF-8"/>
<title>test</title>
<script src="http://cdnjs.cloudflare.com/ajax/libs/phaser-ce/2.8.1/phaser.js"></script>
</head>
<body>
<button id="button">Click</button>
<div id="canvas"></div>
<script>
window.onload = function() {
var d, n, game;
d = document.getElementById('button');
n = document.getElementById('canvas');
function preload() {
}
function create() {
}
function update() {
}
function handler() {
if(game) {
game.destroy();
game = null;
} else {
game = new Phaser.Game({
width: 800,
height: 600,
renderer: Phaser.AUTO,
parent: n,
enableDebug: false,
state: {
preload: preload,
create: create,
update: update
},
});
}
}
d.onclick = handler;
};
</script>
</body>
</html>
Upvotes: 1