JavaScript で作った Canvas ゲームのメモリリークチェックは、主に Chrome DevTools の Memory タブと Performance タブ を使って行います。
Canvas ゲームでよくあるリークは次のようなものです。
- 使わなくなったオブジェクトが配列に残り続ける
setIntervalやrequestAnimationFrameが停止されない- イベントリスナーが解除されない
- Canvas や Image オブジェクトへの参照が残る
- WebGL テクスチャやバッファを解放しない
- シーン切り替え時に古いゲームオブジェクトが残る
1. メモリ使用量を観察する
Chromeでゲームを開き、
F12 → Performance Monitor
を開きます。
メニュー:
DevTools
→ More tools
→ Performance monitor
ここで
- JS heap size
- DOM Nodes
- Event Listeners
を監視できます。
例えば、
- タイトル画面
- ゲーム開始
- ステージ切替
- ゲームオーバー
- タイトルに戻る
を何度も繰り返した際に、
50MB
60MB
70MB
80MB
90MB
のように増え続けるならリークの疑いがあります。
正常なら GC 後にある程度元へ戻ります。
2. Heap Snapshot を取る
最も強力な方法です。
手順
DevTools
Memory
→ Heap Snapshot
→ Take Snapshot
1回目を取得。
その後、
- シーンを何回か切り替える
- 敵を大量生成して削除する
- リスタートを何回か行う
そして2回目を取得。
Comparison表示
2つ目の Snapshot を選択し
Comparison
を見ると
Enemy +5000
Bullet +10000
Particle +30000
など増加したオブジェクトが分かります。
本来削除済みの敵や弾が残っていたらリークです。
3. Retainers を調べる
例えば
Enemy
が残っている場合、
オブジェクトを選択すると
Retainers
に
window
→ Game
→ enemies
→ Enemy
のような参照経路が表示されます。
例えば
game.enemies.push(enemy);
したのに
game.enemies.splice(...)
していない場合、
ここで発見できます。
4. Allocation Timeline を使う
Memory タブで
Allocation instrumentation on timeline
を選択。
録画しながらゲームをプレイします。
すると
毎フレーム
Particle生成
↓
GC後も残存
のようなオブジェクトが見つかります。
ゲームでは特に有効です。
5. requestAnimationFrame のリーク確認
よくあるミス
function startGame() {
requestAnimationFrame(loop);
}
をゲーム再開ごとに呼んでしまう。
結果
loop
loop
loop
loop
が複数走ります。
確認方法:
let frameCount = 0;
function loop() {
frameCount++;
requestAnimationFrame(loop);
}
リスタート後にCPU使用率が増えるなら怪しいです。
6. イベントリスナー確認
例えば
window.addEventListener("keydown", onKeyDown);
をシーン開始時に毎回追加している場合。
Performance Monitor の
Event Listeners
が
20
40
60
80
と増えていきます。
解除:
window.removeEventListener(
"keydown",
onKeyDown
);
7. Canvasゲームでよくあるリーク箇所
弾
bullets.push(new Bullet());
削除忘れ
if (bullet.dead) {
bullets.splice(i, 1);
}
パーティクル
particles.push(...)
寿命終了後も残る
シーン
sceneManager.currentScene
が古いシーンを参照し続ける
キャッシュ
Map
Set
WeakMap
の管理ミス
8. コードで簡易監視
Chrome限定ですが、
setInterval(() => {
console.log(
performance.memory.usedJSHeapSize /
1024 /
1024
);
}, 1000);
でヒープサイズを確認できます。
数分プレイ後に
50MB
52MB
55MB
58MB
61MB
...
と単調増加し続けるなら要調査です。
Canvas ゲームの場合、実務では
- Performance Monitorで増加傾向を見る
- Heap Snapshotを比較する
- Retainersで参照元を特定する
- Allocation Timelineでフレームごとの残存オブジェクトを探す
の順で調査するのが最も効率的です。特に Heap Snapshot の Comparison + Retainers を使えるようになると、ほとんどの JavaScript メモリリークは特定できます。