1.

Unity WebGL のメモリ不足|Out of memory の原因と削り方

編集
この記事の要点
  • WebGL ビルドはブラウザのタブが使えるメモリの中で動く。PC 版より上限がはるかに低い
  • まず Player Settings のメモリ設定を見る。次にアセットの容量を削る
  • 効果が大きいのはテクスチャの圧縮と最大サイズの引き下げ。多くの場合ここが最大の原因
  • 音声は Streaming にする。全部展開してメモリに載せない
  • モバイルのブラウザは特に厳しい。PC で動いてもスマホで落ちることがある

出るエラー

Out of memory. If you are the developer of this content,
try allocating more memory to your WebGL build in the WebGL player settings.

RangeError: Array buffer allocation failed

Uncaught RangeError: Maximum call stack size exceeded

Cannot enlarge memory arrays.

ブラウザの開発者ツール(F12)の Console に出ます。Unity Editor では再現しません。エディタは PC のメモリをそのまま使えるためです。

1. Player Settings のメモリ設定

File → Build Settings → Player Settings → Player
  → Publishing Settings(WebGL タブ)
Unity のバージョン設定項目
2020 以前Memory Size(MB)を手で指定する
2021 以降Initial Memory SizeMemory Growth Mode で自動拡張する

数値を上げれば解決することもありますが、ブラウザが確保できなければ結局落ちます。増やすのは応急処置で、根本はアセットの容量です。

また、Development Build のチェックを外すだけでもメモリと容量が減ります。公開用のビルドでは必ず外してください。

2. テクスチャを削る(最も効果が大きい)

Project ウィンドウで画像を選択 → Inspector
  Max Size            2048 → 1024 や 512 に下げる
  Compression         Normal Quality 以上(None にしない)
  Use Crunch Compression  ON(ダウンロード容量が大きく減る)
  Generate Mip Maps   UI 用のスプライトでは OFF

テクスチャは展開後のサイズがメモリを占めます。2048×2048 の非圧縮 RGBA は約 16MB で、これが 10 枚あれば 160MB です。Max Size を半分にするだけで消費は約 4 分の 1 になります。

複数の画像をまとめて設定するには、Project ウィンドウで複数選択してから Inspector で変更します。

3. 音声を Streaming にする

音声ファイルを選択 → Inspector
  Load Type
    Decompress On Load   … 全部展開してメモリに載せる(短い効果音だけ)
    Compressed In Memory … 圧縮したまま保持する
    Streaming            … 再生しながら読む(BGM はこれ)
  Compression Format     Vorbis
  Quality                70% 前後まで下げても違いは分かりにくい
  Force To Mono          ON(効果音はモノラルで十分。容量が半分になる)

数分の BGM を Decompress On Load にすると、それだけで数十 MB を占めます。長い音声は必ず Streaming にしてください。

4. 使っていないものを含めない

Player Settings → Other Settings
  Managed Stripping Level   High     使っていないコードを削る
  Strip Engine Code         ON

Build Settings → Scenes In Build
  使っていないシーンのチェックを外す

Resources フォルダに置いたものは、使っていなくてもすべてビルドに含まれます。参照していないアセットは Resources から出してください。動的に読み込むなら Addressables を使うと、必要になったときだけ取得できます。

5. ビルドの圧縮設定

Player Settings → Publishing Settings
  Compression Format   Brotli(最も小さい)/Gzip(対応が広い)
  Data Caching         ON(2 回目以降の読み込みが速くなる)

これはダウンロード容量の話で、実行時のメモリ消費そのものは減りません。ただし読み込み中に落ちる場合は改善することがあります

Brotli は配信サーバーが対応していないと動きません。itch.io や Unity Play では対応済みですが、自前のサーバーでは Content-Encoding の設定が要ります。設定が難しいときは Gzip か Disabled を選んでください。

6. 何が重いのかを調べる

ビルド後に Console ウィンドウの右上メニューから
  Open Editor Log
を選ぶと、ビルドに含まれたアセットが容量の大きい順に一覧できる

「Textures 68%」のように種類ごとの割合が出るので、どこを削るべきかが分かります。上位の数個を直すだけで大きく変わることが多いです。

// 実行中のメモリを画面に出して確認する
using UnityEngine;
using UnityEngine.Profiling;

public class MemoryHud : MonoBehaviour
{
    private void OnGUI()
    {
        long used = Profiler.GetTotalAllocatedMemoryLong() / 1024 / 1024;
        long reserved = Profiler.GetTotalReservedMemoryLong() / 1024 / 1024;
        GUI.Label(new Rect(10, 10, 300, 20), $"使用 {used} MB / 確保 {reserved} MB");
    }
}

7. 実行中に増え続ける場合

// 生成したものを破棄していない
Instantiate(prefab);                    // 増え続ける
Destroy(obj);                           // 使い終わったら破棄する

// シーンを切り替えても消えないもの
DontDestroyOnLoad(gameObject);          // 使いどころを限る

// 動的に読み込んだアセットを解放する
Resources.UnloadUnusedAssets();
System.GC.Collect();

// 毎フレームの文字列連結はゴミを増やす
void Update() {
    label.text = "Score: " + score;      // 毎フレーム新しい文字列を作る
}

時間が経つほど重くなる場合は、破棄漏れ(メモリリーク)を疑います。弾やエフェクトのように大量に生成するものは、破棄せず使い回す仕組み(オブジェクトプール)にすると安定します。

8. ブラウザ側の制約

環境傾向
PC の 64bit ブラウザ比較的余裕がある
PC の 32bit ブラウザプロセス全体で 2GB 程度が上限
スマートフォン最も厳しい。PC で動いても落ちることがある
タブを多数開いた状態他のタブに圧迫されて失敗しやすい

Unity 公式もモバイルブラウザは WebGL の動作対象外としています。スマートフォン向けに配信するなら、軽量な内容に絞るか、ネイティブアプリとして出すことを検討してください。

直す順番

  1. Development Build のチェックを外す
  2. Editor Log で何が容量を食っているかを確認する
  3. テクスチャの Max Size を下げ、圧縮を有効にする
  4. 音声を Streaming + モノラルにする
  5. Managed Stripping Level を High にする
  6. 使っていないシーンとアセットをビルドから外す
  7. それでも足りなければメモリ設定を上げる
  8. シーンを分割し、必要なときだけ読み込む

関連

編集
Post Share
子ページ

子ページはありません

同階層のページ

同階層のページはありません

最近更新/作成されたページ