Profilerの記事 でCPUのスパイクは追えるようになった。フレームレートも足りている。なのに——実機で10分遊ぶと突然アプリごと落ちる。ステージから戻って もメモリ使用量が戻らない。ロード画面のたびに端末が熱くなる。
それは 「速さ」ではなく「重さ」の問題、つまり常駐メモリの世界です。この記事では Memory Profiler パッケージを使って、Snapshotの撮り方から、Before/After比較で「居座るメモリ」を突き止める捜査手順、端末ごとのメモリ予算の考え方までを一本道で解説します。
この記事でわかること
- GCスパイク(カクつき)と常駐メモリ(重さ・クラッシュ) の切り分け
- Memory Profilerの導入と Snapshotの撮り方(実機接続)
- Unity Objectsビュー でテクスチャ・Mesh・AudioClipを読む
- Before/After比較 で「シーンを戻っても残るもの」を暴く
- 端末から逆算する メモリ予算 の考え方
- 実践:実機で落ちるステージから100MBを取り戻す
動作確認環境: Unity 2022.3 LTS / Unity 6・Memory Profiler 1.1+
「GCスパイク」と「常駐メモリ」は別の病気
メモリの問題は、大きく2種類に分かれます。症状も道具も対処も違うので、最初に切り分けます。

- GCスパイク: 毎フレーム生まれては捨てられる短命なゴミ(文字列連結、newの乱発)が溜まり、回収の瞬間に カクッと止まる。道具は通常のProfiler、対処は GC最適化の記事 の領域です
- 常駐メモリ: テクスチャ・Mesh・オーディオなどが読み込まれたまま 居座り続ける。症状はアプリ全体の重さ、ロードの遅さ、そしてモバイルでは OSによる無言の強制終了 です。クラッシュログすら残らないことが多く、「実機でだけ、忘れた頃に落ちる」という一番タチの悪い形で現れます
この記事が相手にするのは後者です。フレームレートのグラフをいくら眺めても常駐メモリは見えません。専用の道具——Memory Profilerが要ります。
Memory Profilerを入れて、Snapshotを撮る
Memory Profiler はPackage Manager(Unity Registry)から Memory Profiler を追加すると、Window > Analysis > Memory Profiler で開けます。
通常のProfilerが「毎フレームの流れ」を見る動画だとすれば、Memory Profilerは 「その瞬間のメモリの中身ぜんぶ」を写す写真(Snapshot) です。使い方は3手順です。
- 実機のDevelopment Buildを起動して接続する: ビルド設定でDevelopment Buildを有効にしてビルドし、実機で起動。Memory Profilerウィンドウ上部の接続先ドロップダウンで、Editorではなく 実機のPlayerを選びます
- Captureボタンで撮る: 数秒かかってSnapshotが保存されます
- 調べたい場面ごとに撮る: タイトル画面で1枚、重いステージで1枚、ステージから戻って1枚——比較こそがこの道具の本体なので、 場面の「前後」で撮る のが基本動作です
注意: Editorに接続して測った数値は参考になりません。Editorはエディタ自身の管理データやSceneビューのために、実際のゲームの何倍もメモリを使っています。「実機で落ちる」問題は、必ず実機のPlayerに接続して調べてください。
読み方:何が場所を食っているのか
Snapshotを開いたら、まず Summaryビュー で全体の内訳を見ます。だいたいのゲームで、主役は次の顔ぶれです。
| 項目 | 中身 | 太りやすさ |
|---|---|---|
| Texture2D | テクスチャ。UI・スプライト・モデルの絵 | ★★★(ほぼ主犯) |
| Mesh | 3Dモデルの形状データ | ★★ |
| AudioClip | BGM・効果音 | ★★(設定次第で激変) |
| Managed Heap | C#のオブジェクト(List、クラスのインスタンス等) | ★(漏れの温床) |
| Graphics / RenderTexture | 描画用のバッファ類 | ★ |
次に Unity Objectsビュー に切り替えて、 サイズの降順に並べます。これがメモリ捜査の基本姿勢です——「何百個の小物」より「上位10個の大物」が勝負を決めます。2048×2048の非圧縮テクスチャ1枚は約16MB。同じ絵でも圧縮フォーマット(モバイルならASTCなど)が効いていれば数MBで済みます。上位に並ぶテクスチャの名前とサイズを見るだけで、「このタイトルロゴ、4Kのままだ」のような発見が始まります。
Before/After比較:戻っても残るものを暴く
Memory Profilerの真価は 2枚のSnapshotの比較(Compare) にあります。狙い撃ちたいのは、こういう質問です——「ステージから戻ったのに、なぜメモリが戻らないのか?」

手順は儀式のように固定します。
- タイトル画面でSnapshot A を撮る
- 重いステージへ行き、ひと通り遊んで、 タイトルへ戻る
- 戻った直後に Snapshot B を撮る
- Memory Profilerで2枚を開き、 Compareモード で差分を見る
理屈のうえでは、AとBは同じタイトル画面なので中身はほぼ同じはずです。 Bにだけ残っているもの——それが「シーンを戻っても解放されなかった」容疑者リスト です。ステージのボステクスチャがタイトルに戻っても居座っていたら、何かがそれを掴んでいます。定番の犯人は4人です。
- staticフィールドの参照:
static List<Enemy>に入れたまま忘れた敵のデータ - 解除し忘れたイベント購読: 破棄されたはずのUIが、staticイベント経由でアセットを間接的に掴んで いる(イベントの記事 の解除ルールはメモリの話でもあります)
- DontDestroyOnLoadのオブジェクト: シーンをまたいで生き残る設計のものが、ステージ専用アセットまで道連れに保持している
- Releaseしていないアドレサブル: Addressablesの記事 の「借りたら返す」を破っているハンドル
比較ビューで容疑者を選ぶと、 何がそれを参照しているか(References) を辿れます。「誰が掴んでいるのか」まで特定できれば、修正は一直線です。
メモリ予算:端末から逆算する
漏れを塞いだら、次は「そもそも何MBまでならいいのか」です。答えは端末側にしかありません。モバイルのOSは、空きメモリが逼迫すると 警告なしでアプリを強制終了します。PCと違って「重いけど動く」が存在しない世界です。
現実的な方法は、 ターゲット最低スペックの実機を1台決めて、そこで落ちない上限を計測し、それをカテゴリに配る ことです。

配分そのものはゲームによりますが、考え方は共通です。
- 一番大きな財布はテクスチャに(そして一番削りやすいのもテクスチャ。解像度と圧縮設定で数分の一になります)
- 「余白」を必ず残す: シーン切り替えの瞬間は、新旧両方のアセットが同時に載る山場です。予算いっぱいまで使う設計は、ロードの瞬間に死にます
- 予算はチェック表で運用する: 「同じ端末・同じ手順・同じ場面」でSnapshotを撮り、修正前後の数値を並べて記録します。測り方が毎回違うと、改善したのか誤差なのか永遠に分かりません
実践:落ちるステージから100MBを取り戻す
架空だけれど毎日どこかで起きている事件を、通しで捜査してみましょう。 「ステージ3だけ、古い端末で高確率で落ちる」。フレームレートは正常。ログには何も残っていない——常駐メモリの典型的な現場です。

- 実機Playerに接続し、ステージ3の直前と直後でSnapshotを撮る。直後の1枚のSummaryを見ると、Texture2Dが全体の6割を占めている
- Unity Objectsビューをサイズ降順に。最上位に見覚えのない
BG_Stage3_Skyが48MB——4096×4096・非圧縮・しかもmipmapまで付いている。次点に、ほぼ同サイズのBG_Stage3_Sky_old(使っていない旧版まで参照されて載っている) - Import設定を修正する: 空のテクスチャに4096は要らないので2048へ、圧縮をASTCへ、UI用ならmipmapをオフに。旧版はそもそも参照を断つ。この2枚だけで約90MBが消える
- 同じ手順でもう一度Snapshotを撮り、Compareで確認: Texture2Dの合計が下がったこと、消したはずの旧版が本当に消えたことを、目で確かめる
- 実機でステージ3を3周して、落ちないことを確認。チェック表に「修正前348MB → 修正後251MB・3周クラッシュなし」と記録して事件解決です
ポイントは2つ。 捜査は常にサイズの大きい順(上位10件を疑うだけで大半の事件は解決します)。 修正の確認まで同じ端末・同じ手順で(測り方を揃えて初めて、数値は証拠になります)。
おまけ:先に知っておくと良いこと
- AudioClipは設定で激変する: 長いBGMの Load Type が
Decompress On Loadになっていると、圧縮を解いた生データがまるごとメモリに載ります(数十MB級)。BGMはStreamingにするのが定番です - 「読み込んだだけ」のResourcesに注意:
Resources.Loadしたアセットは、参照が切れてもResources.UnloadUnusedAssets()(シーン遷移時に自動実行)まで残ることがあります。手動で大きなアセットを読むなら、手動で片付ける意識を - テクスチャ予算はプラットフォーム別に: Import設定のプラットフォーム別オーバーライドで、モバイルだけ解像度と圧縮を落とせます。PC向けの見た目を保ったままモバイルの予算に収める正攻法です。詳しくは モバイル最適化の記事 へ
まとめ
- カクつきは GCスパイク、実機の重さとクラッシュは 常駐メモリ。別の病気、別の道具
- Memory Profilerは その瞬間の写真(Snapshot)。必ず 実機のPlayerに接続 して撮る
- 読み方の基本は Unity Objectsビューをサイズ降順。主犯はほぼテクスチャ
- Before/After比較 で「戻っても残るもの」を暴く。犯人はstatic参照・イベント解除忘れ・DontDestroyOnLoad・未Release
- 予算は ターゲット実機で計測して逆算。余白を残し、チェック表で修正前後を比べる
あなたのゲームのいちばん重いシーン、Texture2Dの上位10件に、いま何が並んでいるか言えますか? 言えなければ——Snapshotを1枚撮るところから始めましょう。