JavaScript | Web API:パフォーマンス・セキュリティ - メモリ監視

JavaScript JavaScript
スポンサーリンク

「メモリ監視」は“どれだけ詰め込んでいて、どれだけ片付いていないか”を見ること

パフォーマンスは「速さ」だけじゃなくて、「どれだけメモリを使っているか」も重要です。
メモリを使いすぎると、ブラウザが重くなったり、最悪タブがクラッシュします。

JavaScript ではガベージコレクション(不要になったものを自動で片付ける仕組み)があるので、
「メモリ管理なんて気にしなくていい」と思われがちですが、
実際は「片付けられない状態を自分で作ってしまう」ことがよくあります。

メモリ監視は、
今どれくらいメモリを使っているか
処理を繰り返すとメモリが増え続けていないか
「片付け忘れ」が起きていないか
を数字で確認するための視点です。

ここでは、ブラウザでできる範囲のメモリ監視を、初心者向けにかみ砕いて話します。


まずは「メモリリークって何?」をイメージで掴む

使い終わったのに、ずっと残り続ける状態

メモリリークとは、本来いらなくなったデータが、
何かの参照が残っているせいで、ずっとメモリに居座り続ける状態です。

例えば、こんなイメージです。

大きな配列を作る
使い終わったのに、どこかの変数がその配列を指し続けている
結果として、ガベージコレクタが「もう捨てていい」と判断できない

コードでいうと、こういうパターンです。

const cache = [];

function addBigData() {
  const big = new Array(1000000).fill("hello");
  cache.push(big);
}
JavaScript

addBigData() を何度も呼ぶと、
cache にどんどん大きな配列が溜まっていきます。
どこからも参照されなくなれば捨てられますが、
cache が持ち続けている限り、メモリは増え続けます。

これが「意図せず起きる」と、
気づかないうちにメモリが膨らんでいきます。


ブラウザでメモリを“ざっくり”見る方法(DevTools)

まずは「増え続けていないか」を見る

一番現実的で初心者におすすめなのは、
ブラウザの DevTools(開発者ツール)を使う方法です。

Chrome を例にすると、
DevTools を開いて、Performance や Memory タブから
メモリの使用量をグラフで見ることができます。

やることのイメージはシンプルです。

ページを開く
特定の操作を何度も繰り返す(画面遷移、モーダル表示など)
メモリグラフが「山になって下がる」のか、「階段状に上がり続ける」のかを見る

山になって下がるなら、
一時的にメモリを使っても、ちゃんと解放されている可能性が高いです。

階段状に上がり続けるなら、
どこかで「片付け忘れ」が起きている可能性が高いです。

ここで大事なのは、
「完璧に理解する」ことではなく、
「増え続けているかどうか」を感覚として掴むことです。


JavaScript からメモリを覗く API(performance.memory)

Chrome など一部ブラウザで使える非標準 API

ブラウザによっては、
performance.memory というオブジェクトが使えることがあります(主に Chrome 系)。

例えば、こんな感じです。

if ("memory" in performance) {
  console.log(performance.memory);
}
JavaScript

中身の例はこんなイメージです。

{
  usedJSHeapSize: 12345678,
  totalJSHeapSize: 34567890,
  jsHeapSizeLimit: 2190000000
}
JavaScript

usedJSHeapSize は、今 JavaScript が使っているヒープメモリの量
totalJSHeapSize は、確保されているヒープ全体のサイズ
jsHeapSizeLimit は、ブラウザが許してくれる上限

というイメージです。

これを使って、
処理の前後で usedJSHeapSize を比較することで、
「この処理でどれくらいメモリを増やしているか」を見ることができます。

ただし、これは非標準で、ブラウザによっては使えません。
「使えたらラッキー」くらいの位置づけで覚えておくといいです。


簡単な「メモリ増え続けチェック」の例

意図的にメモリを食う処理を書いて、変化を見る

例えば、こんなコードをブラウザのコンソールで試してみます。

const bigArrayStore = [];

function allocate() {
  const big = new Array(500000).fill("x");
  bigArrayStore.push(big);
}

function logMemory() {
  if (!("memory" in performance)) {
    console.log("performance.memory はこのブラウザでは使えません");
    return;
  }
  const m = performance.memory;
  console.log(
    "usedJSHeapSize:",
    (m.usedJSHeapSize / 1024 / 1024).toFixed(2),
    "MB"
  );
}
JavaScript

これを使って、次のように動かします。

logMemory();      // 今のメモリ使用量
allocate();       // 大きな配列を 1 個追加
logMemory();      // 増えたかどうかを見る
allocate();       // さらに追加
logMemory();      // さらに増えたかを見る
JavaScript

usedJSHeapSize が
どんどん増えていくのが見えるはずです。

ここで重要なのは、
「こういうコードを書けば、メモリが増え続ける」という感覚を掴むことです。

逆に、参照を切れば解放されます。

bigArrayStore.length = 0; // 配列を空にする
logMemory();              // しばらくすると減ってくる(ガベージコレクション次第)
JavaScript

ガベージコレクションはすぐには走らないので、
即座に減らないこともありますが、
時間をおいて何度か log を見ると、
減っていくのが分かることがあります。


メモリリークを起こしやすい典型パターンを知っておく

setInterval やイベントリスナーの「付けっぱなし」

初心者が一番やりがちなメモリリークは、
「永遠に動き続けるものを止めない」パターンです。

例えば、setInterval

setInterval(() => {
  const big = new Array(100000).fill("hello");
  console.log(big[0]);
}, 1000);
JavaScript

この中で作った配列は、
コールバックの中だけで完結していれば、
毎回捨てられます。

しかし、どこかに貯め始めると危険です。

const store = [];

setInterval(() => {
  const big = new Array(100000).fill("hello");
  store.push(big); // どんどん溜まる
}, 1000);
JavaScript

これは、1 秒ごとにメモリを増やし続ける爆弾です。

同じように、イベントリスナーも
「付けたけど、もう使わないのに remove していない」
という状態が積み重なると、
本来捨てられるはずのオブジェクトが残り続けます。

例えば、モーダルを開くたびに新しいリスナーを付けて、
閉じるときに外さない、などです。

メモリ監視の観点からは、
「永続的なものを増やすときは、本当に必要か?」
「いつ解放されるのか?」
を意識することが大事です。


「監視」と「片付け」をセットで考える

監視はあくまで“気づくための道具”

メモリ監視は、
「問題に気づくための道具」であって、
「問題を自動で直してくれるもの」ではありません。

DevTools のグラフや performance.memory を見て、
メモリが増え続けていると分かったら、
次にやるべきことはコードの見直しです。

どこで大きな配列やオブジェクトを作っているか
どこでそれを保持し続けているか
本当に保持し続ける必要があるのか
イベントリスナーやタイマーを付けっぱなしにしていないか

こういう視点でコードを読み直していきます。

初心者のうちは、
「メモリ監視で完璧に原因を特定する」必要はありません。
まずは、

メモリが増え続けているかどうかを見てみる
怪しそうなコード(大きな配列、永続的な配列、setInterval など)を疑ってみる

この二段階だけでも、
「なんとなく」から一歩抜け出せます。


初心者として「メモリ監視」で掴んでほしい感覚

メモリ監視は、
いきなりプロレベルのツールを使いこなす必要はありません。

まずは、次の感覚を持てれば十分です。

メモリは「使えば使うほど重くなる」ので、増え続けていないかを見る
大きなデータをどこかに貯め続けると、簡単にメモリリークになる
setInterval やイベントリスナーの「付けっぱなし」は特に危険
DevTools のメモリグラフや、あれば performance.memory で「増え方」を眺めてみる

パフォーマンスを気にするエンジニアは、
「速さ」と「メモリ」の両方を意識します。

あなたが「この処理、時間だけじゃなくてメモリも食ってないかな?」と
一度でも立ち止まれるようになったら、
それだけで一段上の視点に来ています。

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