Canvasゲームのリークチェック

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

を監視できます。

例えば、

  1. タイトル画面
  2. ゲーム開始
  3. ステージ切替
  4. ゲームオーバー
  5. タイトルに戻る

を何度も繰り返した際に、

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 ゲームの場合、実務では

  1. Performance Monitorで増加傾向を見る
  2. Heap Snapshotを比較する
  3. Retainersで参照元を特定する
  4. Allocation Timelineでフレームごとの残存オブジェクトを探す

の順で調査するのが最も効率的です。特に Heap Snapshot の Comparison + Retainers を使えるようになると、ほとんどの JavaScript メモリリークは特定できます。

タイトルとURLをコピーしました