6
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Unity】MemoryProfilerでメモリ蓄積を調査する手順

Posted at

この記事は Unity Advent Calendar 2025 の10日目の記事です。

経緯

Android 実機で突然アプリクラッシュした経験があったので、その振り返りとしてまとめています。
メモリリークに近い内容ですが、C#の参照が残っているためGC(ガベージコレクション)で回収されないメモリについての話になります。

環境

  • Unity 6000.0.31f1
  • Memory Profiler 1.1.9

古いUnityバージョンでも手順はおおむね同じです。

前準備

PackageManagerからMemoryProfilerをインストールします。
インストールできていればProfilerを開いて、Memoryタブを選択すると、Open Memory Profilerが有効になります。

image.png

調査のしかた

メモリの蓄積を調べるには、ある時点からある時点のメモリアロケーションのスナップショットの差分を取り、アロケーションが増えていることを確認します。

手順は以下になります。

  • メモリが蓄積される部分をProfilerで計測
  • ある時点のスナップショットAを撮影
  • ある時点のスナップショットBを撮影
  • スナップショットA・Bを比較
  • アロケーション箇所を特定
今回のサンプルコード
Sample.cs
using UnityEngine;
using System.Collections.Generic;

public class Sample : MonoBehaviour
{
    private readonly List<byte[]> _leakList = new List<byte[]>();

    void Update()
    {
        byte[] data = new byte[1024 * 1024]; // 1MB

        // コンパイラのストリップを防ぐためのダミー処理
        data[0] = (byte)(Time.frameCount % 255);

        // 参照を保持してGCに乗せない
        _leakList.Add(data);

        // 現在の確保済みサイズを表示
        Debug.Log($"[Leaker] Allocated: {_leakList.Count} MB");
    }
}

まず Profiler で計測して、蓄積前にシークを動かし、MemoryProfiler を開きます。

image.png

Memory Profilerのウィンドウが表示されます。

image.png

左上のカメラマークのCapture、中央のCapture New Snapshotを押すとスナップショットが撮れます。

「メモリに見られたらまずいデータがある場合は共有に気を付けてね」と警告が出る場合は、理解したうえでTake Snapshotを押してください。

image.png

しばらく待つとスナップショットが完了します。

Profilerに戻り、蓄積されているフレームを選択して、再びMemory ProfilerCaptureを押してください。
左のSessionの欄にスナップショットが並んでいきます。

image.png

Sessionに並んでいるスナップショットのプロジェクト名を選択すると、名前が編集できます。
スナップショットは上から下に新しいものが並びますが、回数が増えると、どれが対となるデータか分からなくなってくるので、適宜名前を付けていきましょう。

上のSingle SnapShotをCompare Snapshotsに切り替えます。

image.png

2つNo snapshot selected.と表示されており、これは比較前(上)、比較後(下)となります。
この状態でSession欄の比較前のスナップショットを選択します。

image.png

そして、比較後のスナップショットを選択します。
ⒶとⒷのしるしが付いていれば、正しく選択できています。

image.png

Ⓐが比較前、Ⓑが比較後のスナップショットの対象とされます。
選択されたスナップショットのTotal Resident等で見て、選択間違えが起きてないかチェックしましょう。

この状態になれば、スナップショットの差分から原因を特定するフェーズになります。

分析

上部にタブでアロケーションの種類別にみることができます。

  • Summary
    • 全体的に差分が確認できます
    • 最初に調査のアタリ付けたい場合はここを見ます
  • Unity Objects
    • Unity オブジェクトのアロケーションの一覧です
    • リークのマーキングや参照元がわかるため、メモリリークした場合はすぐに発見できます
  • All Of Memory
    • 全てのアロケーションの一覧です
    • アタリが付けにくい場合は、ここを見て細かく調査できます

今回はAll Of Memoryタブに切り替えて調査します。

image.png

中央のリストはどういうメモリが確保されているかの詳細です。

image.png

メモリの区分けはざっくり以下の通りです。

  • Managed
    • C#側のメモリ
  • Native
    • C++側のメモリ
  • Executables & Mapped
    • プロセスレベルのメモリ
  • Graphics(Estimated)
    • グラフィックスドライバとGPUのメモリ
  • Untracked*
    • 上記で網羅できなかったメモリ

Unityスクリプトの場合は、NativeManagedの2つが調査対象の中心になります。

Count Differenceがアロケーションの回数差分、Size Differenceがアロケーションのメモリサイズ差分です。

Size Differenceが大きいManagedの中のManaged Objectsを見ると、どのような型でアロケーションされたかわかります。

image.png

アプリケーションの状態から心当たりがあるアロケーション探っていきます。

心当たりのあるものを見つけたら開き、一つアロケーションを選択します。
すると、右側に参照情報が表示されます。

image.png

Referenced By(参照元)とReferences To(参照先)のタブがあります。

ここで重要なのが、Referenced Byの情報です。
このツリーを下に辿っていくことで、大元の参照保持のオブジェクトが見つかります。

image.png

あとはコードを確認し、以下のような点を見直して修正を行います。

  • イベントの購読寿命を間違えてないか
  • Clear()Dispose()を呼び忘れてないか
  • TaskUniTaskのキャンセル処理を正しく行われているか

以上が調査する流れになります。

まとめ

Memory Profilerはグラフを多くウッとなりますが、見方がわかると簡単にメモリアロケーションを調査することができます。
不可解なアロケーションをなくしてUXを上げていきましょう。

参考文献

6
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?