1. 導入:なぜHeap Snapshotの比較が重要なのか
Webアプリケーションが長期間稼働するにつれ、「ページが徐々に重くなる」「ブラウザがクラッシュする」といった現象に遭遇したことはありませんか?その多くはメモリリークが原因です。一度確保したメモリが解放されず、ゴミとして蓄積され続けることで発生します。本記事では、Chrome DevToolsの「Heap Snapshot」機能を活用し、メモリの増減を可視化して、リークの犯人を論理的に特定する手法を解説します。
2. 基礎知識:メモリ差分分析とは
「Heap Snapshot」とは、その瞬間にメモリ上に存在する全てのオブジェクトを記録した地図のようなものです。
メモリ差分分析(Heap Snapshot Comparison)とは、特定の操作(ボタンクリックや画面遷移など)の「前」と「後」で計2回スナップショットを取得し、その差分だけを抽出して解析する手法です。これにより、「どのクラスや関数がメモリを大量に消費しているか」「解放されるべきDOM要素がなぜか残っているか」を即座に特定できます。
3. 実装・解決策:メモリリークを特定する3ステップ
具体的な手順は以下の通りです。
1. Chrome DevToolsの「Memory」タブを開き、「Heap snapshot」を選択して1回目のスナップショットを取得します。
2. リークが疑われる操作(例:モーダルの開閉を5回繰り返す)を実行します。
3. 再度スナップショットを取得し、比較モード(Comparison)に切り替えて「#Delta(差分)」列で降順ソートします。
ここで「#Delta」がプラスになっている項目が、操作後に消えずに残っている「メモリリークの容疑者」です。
4. サンプルプログラム:メモリリークを引き起こすコードと検証
以下のコードは、配列に要素を追加し続けることでメモリリークを意図的に発生させるサンプルです。このコードを実行した後にSnapshotを取得・比較すると、`leakyArray`が肥大化していることが確認できます。
// メモリリークを再現するサンプルコード
const leakyArray = [];
function addData() {
// 10万個の巨大なオブジェクトを配列に追加し続ける
for (let i = 0; i < 100000; i++) {
leakyArray.push({
id: i,
data: new Array(1000).fill('leak') // 大量のメモリを消費するデータ
});
}
console.log('データが追加されました。メモリ使用量を確認してください。');
}
// ブラウザのコンソールで addData() を実行し、
// 実行前と実行後にHeap Snapshotを比較してみてください。
5. 応用・注意点:現場でのプロファイリングのコツ
現場でデバッグする際は、以下の点に注意してください。
・ガベージコレクション(GC)の強制実行:スナップショットを撮る直前に、DevTools内のゴミ箱アイコン(Collect garbage)をクリックしてください。これにより、GCによって回収可能な不要メモリを一旦クリーンにし、より正確な「本当にリークしているデータ」だけを抽出できます。
・DOMのライフサイクル:特にVueやReactなどのフレームワークを使用している場合、コンポーネントが破棄された後もDOMが残っていないかを確認する際にこの手法が非常に有効です。
・過度な期待をしない:最初は「#Delta」の値が大きくても、単なるキャッシュや初期化処理である場合もあります。何度も操作を繰り返しても「#Delta」が増え続けるものこそが、真のメモリリークです。
この手法をマスターすれば、勘に頼ったデバッグから卒業し、データに基づいた確実なパフォーマンスチューニングが可能になります。ぜひ今日の業務から取り入れてみてください。

コメント