Blob URL (createObjectURL) と Base64 Data URL の性能比較とメモリ管理

JavaScript Frontend Performance WebAPI
結論

画像プレビュー等には URL.createObjectURL() を使い、表示後に URL.revokeObjectURL() で解放します。

// MDN公式仕様:Blob URL の生成と安全なメモリ解放
function previewImage(file) {
  const objectUrl = URL.createObjectURL(file);
  const img = document.createElement('img');
  img.src = objectUrl;

  img.onload = () => {
    // ⭕ 描画完了後、メモリ参照を明示的に開放(メモリリーク防止)
    URL.revokeObjectURL(objectUrl);
  };

  document.body.appendChild(img);
}

MDN公式仕様:2つの手法の性能比較マトリクス

評価軸Blob URL (createObjectURL)Base64 Data URL (readAsDataURL)
文字列のサイズ非常に短い短縮ポインタ URL元データより約 33% 肥大化
生成パフォーマンス超高速 (ポインタ生成のみ 0ms)× CPU負荷の高いテキスト変換処理が必要
メモリ解放URL.revokeObjectURL() の明示が必要ガベージコレクションで自動解放
Service Worker❌ Service Worker内では使用不可◯ 文字列として透過処理可能

実際に起こる事故:URL.revokeObjectURL() 忘れによるタブクラッシュ

MDN公式ドキュメント(URL.createObjectURL)で警告されている通り、生成された Blob URL は、明示的に URL.revokeObjectURL() が呼び出されない限り、ページが閉じられる(アンロード)までブラウザの内部メモリ内にデータを維持し続けます。

画像アップロードや動的CSVダウンロードが頻繁に行われるSPA(Single Page Application)において、revoke 漏れの Blob URL を生成し続けると、ブラウザのメモリ(RAM)が数GBまで膨れ上がり、スマートフォンやスペックの低い端末でタブがクラッシュ(OOM)する障害 が発生します。


メモリリーク防止の手順

  1. <img src={url} /><a> タグのダウンロード生成時に URL.createObjectURL(blob) を使用する
  2. img.onload または React の useEffect クリーンアップ関数内で URL.revokeObjectURL(url) を呼び出す
  3. 数KB以下の極小アイコンやインライン埋め込み以外で Base64 文字列を使用しない