Low-Level Memory Tracker (LLM トラッカー) とは、Unreal Engine (UE) プロジェクトでのメモリ使用量をトラックするツールです。LLM では、スコープ付きのタグ システムを使用して、Unreal Engine と OS によってアロケートされたすべてのメモリの記録を維持します。LLM は、Unreal Engine がサポートするすべてのプラットフォームに対応しています。
LLM トラッカー
現在 LLM には 2 つのトラッカーがあり、それぞれには独自のアロケーション マップとタグ スタックが備わっています。「デフォルト トラッカー」は、エンジンからのすべてのアロケーションに対応します。これは 2 つのうちのレベルが高いほうで、FMemory
クラス関数の Malloc
を通じて行われたアロケーションを記録します。このトラッカーにより、stat LLM
と stat LLMFULL
のコンソール コマンドに統計情報が供給されます。レベルが低いほうのトラッカーは「プラットフォーム トラッカー」と呼ばれ、OS によるアロケーションをすべて記録します。たとえば、Binned2
といった関数による内部アロケーションがトラックされます。したがって、デフォルト トラッカーの統計情報は、プラットフォーム トラッカーの統計情報のサブセットということになります。
LLM 設定
プロジェクトで LLM を有効にするには、次のコマンドライン引数とコンソール コマンドを使用します。
コマンドライン引数 | 説明 |
---|---|
-LLM |
LLM を有効にします。 |
-LLMCSV |
すべての値を継続的に CSV ファイルに書き出します。-LLM が自動的に有効になります。 |
-llmtagsets=Assets |
実験的機能です。各アセットによってアロケートされる合計を表示します。 |
-llmtagsets=AssetClasses |
実験的機能です。各 UObject クラス タイプの合計を表示します。 |
コンソール コマンド | 説明 |
---|---|
stat LLM |
LLM の概要を表示します。すべての低レベルのエンジン統計情報は、単一の Engine 統計情報にまとめられます。 |
stat LLMFULL |
すべての LLM 統計情報を表示します。 |
stat LLMPlatform |
OS からアロケートされたすべてのメモリの統計情報を表示します。 |
stat LLMOverhead |
LLM によって内部で使用されるメモリ量を表示します。 |
-LLMCSV
コマンドライン引数を使った場合は .CSV
ファイルが「saved/profiling/llm/
」に書き出されます。このファイルには、現在値を MB 単位で示す、タグごとの列が含まれています。デフォルトで、新しい行が 5 秒ごとに書き込まれます。この頻度は、LLM.LLMWriteInterval
コンソール変数を使って変更できます。
LLM タグ
エンジンによるすべてのメモリ アロケーション (ゲーム コードを含む) には、属するカテゴリを識別するタグ値が割り当てられます。つまり、すべてのメモリは一度だけトラックされて、そこから漏れたり、複数回カウントされたりすることはありません。すべてのカテゴリの合計は、ゲームで使用されるメモリ量の合計になります。
タグは、タグ-スコープのマクロを使って適用されます。このスコープ内で行われるアロケーションには指定したタグが与えられます。LLM によってタグ スコープのスタックが維持され、一番上のタグがアロケーションに適用されます。LLM 統計情報は、stat LLM
または stat LLMFULL
のコンソール コマンドを使ってゲーム内に表示できます。各タグの現在の合計が MB 単位で表示されます。また、LLM によって統計値が .CSV
ファイルに書き出されるため、それらの値を分析することもできます。現在エンジン内にあるタグ カテゴリは次のとおりです。
タグ名 | 説明 |
---|---|
UObject | これには、UObject から継承するあらゆるクラスと、そのクラスによってシリアル化されたあらゆるもの (プロパティを含む) が含まれます。UObject は、他のカテゴリでトラックされていないすべてのエンジンとゲーム メモリに対応します。この統計情報には、個別にトラックされるメッシュやアニメーションのデータは含まれていません。統計情報は、レベル内に配置されたオブジェクトの数に基づいています。 |
EngineMisc | 他のカテゴリでトラックされない低レベル メモリです。 |
TaskGraphTasksMisc | 独自のカテゴリを持たないタスク グラフから開始されるタスクです。全般的には低レベルになります。 |
StaticMesh | UStaticMesh クラスと関連するプロパティです。実際のメッシュ データは含まれません。 |
カスタム タグ
Unreal Insights を使ってプロジェクトのメモリ使用量をプロファイリングする際に、Memory Insights 内で「LLM Untracked (LLM トラッキングなし)」とタグ付けされたアロケート済みのメモリがある場合があります。LLM_DECLARE_TAG
と LLM_DEFINE_TAG
のマクロを使ってカスタム タグを作成することで、トラックされていないメモリ アロケーションを検出しやすくなります。これらのマクロはエンジン ファイルの変更を必要とせず、ゲーム モジュールまたはプラグイン内で実行できます。作成したカスタム タグを使用するには、LLM_SCOPE_BYTAG
マクロを使用します。手順は次のとおりです。
- ヘッダ ファイル内のカスタム LLM タグを
LLM_DECLARE_TAG
で宣言します。 LLM_DEFINE_TAG
を使い、関連する.cpp
ファイル内でカスタム LLM タグを定義します。- メモリ使用量をトラックするスコープを示す
LLM_SCOPE_BYTAG
を.cpp
ファイル内でLLM_SCOPE_BYTAG
とともに使用します。
カスタム タグの宣言と使用に関する例については、後述の「例」を参照してください。
カスタム タグのマクロ
LLM_DECLARE_TAG
LLM_DECLARE_TAG
マクロでは、別の場所で定義されて LLM_SCOPE_BYTAG
で使用可能なタグ、または他の LLM_SCOPE
で名前で参照可能なタグを宣言します。
- パラメータ
UniqueName
:名前で参照するためのタグの名前です。LLM_DEFINE_TAG
、LLM_SCOPE
、またはELLMTag
に渡されるタグの中で固有の名前にする必要があります。
LLM_DEFINE_TAG
LLM_DEFINE_TAG
マクロでは、LLM_SCOPE_BYTAG
で使用可能なタグ、または他の LLM_SCOPE
で名前で参照可能なタグを定義します。
- パラメータ
UniqueNameWithUnderscores
:タグの名前の変更版です。名前による参照で使用されます。LLM_DEFINE_TAG
、LLM_SCOPE
、またはELLMTag
に渡されるすべてのタグの中で固有である必要があります。LLM_DEFINE_TAG
では、親の通常のセパレータ (/
) を (_
) に置き換える必要があります。DisplayName
:(任意)UniqueName
を使用する親またはNAME_None
がある場合に、親の名前に (/
) で参加したタグのトレース時に表示する名前です。ParentTagName
:(任意) 親がない場合に、親タグまたはNAME_None
の固有の名前になります。StatName
:(任意) LLM データをフレームごとに発行する際に、このタグの量とともに入力する統計情報の名前です。統計情報を入力しない場合はNAME_None
を使用します。SummaryStatName
:(任意) LLM データをフレームごとに発行する際に、このタグの量に加える統計情報グループの名前です。統計情報グループを加えない場合は、NAME_None
を使用します。
例
CustomTagExample.h
#pragma once
...
LLM_DECLARE_TAG(MyTestTag);
CustomTagExample.cpp
LLM_DEFINE_TAG(MyTestTag);
AMyActor::AMyActor()
{
LLM_SCOPE_BYTAG(MyTestTag);
MyLargeBuffer.Reset(new uint8[1024*1024*1024]);
}
タグ セット (実験的機能)
タグ セットを使用するには、LLM_ALLOW_ASSETS_TAGS
を「LowLevelMemTracker.h
」内で定義します。タグ セットを使用する際は、それぞれのアロケーションによってアセット名またはオブジェクト クラス名が追加で格納されます。
実装の技術的詳細
LLM は、ポインタによってインデックス化されるすべてのアロケーションのマップを維持することで動作します。現在、マップには各アロケーションのサイズと、割り当てられたタグが含まれます。ゲームでは一度に 400 万にも及ぶライブ アロケーションが生じることがあるため、メモリのオーバーヘッドをできる限り少なく保つことが重要になります。現在の実装では、一つのアロケーションに 21 バイトを使用します。
アロケーション | サイズ |
---|---|
ポインタ | 8 バイト |
ポインタのハッシュ キー | 4 バイト |
サイズ | 4 バイト |
タグ | 1 バイト |
ハッシュ マップ インデックス | 4 バイト |
OnLowLevelAlloc
関数を使ってアロケーションをトラックする場合は、タグ スタックの一番上にあるタグが現在のタグになり、そのポインタをキーとしてアロケーション マップに格納されます。コンテンションを避けるために、各タグのフレームのデルタが個別の FLLMThreadState
クラス インスタンスでトラックされます。フレームの終わりにこれらのデルタが合算されて、その結果が統計情報システムと .CSV
ファイルに発行されます。
LLM は非常に早い段階で初期化されるため、これをデフォルトで有効にしておく必要があります。コマンドラインで LLM が有効になっていない場合は、LLM が自身をシャットダウンしてすべてのメモリをクリーンアップし、オーバーヘッドが生じないようにします。この場合、LLM はテスト ビルドとシッピング ビルドから完全に除外されます。
LLM は統計情報システムなしでも実行できます。たとえば、テスト コンフィグの場合などです。画面上に統計情報を表示することはできませんが、.CSV
ファイルには統計情報が書き出されます。LLM は、「LowLevelMemTracker.h
」ファイルの ENABLE_LOW_LEVEL_MEM_TRACKER
を変更して有効にする必要があります。
タグは、スコープ マクロを使って適用されます。主なマクロとして次の 2 つがあります。
LLM_SCOPE(Tag)
LLM_PLATFORM_SCOPE(Tag)
これらは、それぞれデフォルト トラッカーとプラットフォーム トラッカーの現在のスコープを設定します。こうしたスコープにはプラットフォームに依存するバージョンがあり、たとえば、プラットフォーム固有のタグ列挙型を使う LLM_SCOPE_[Console](Tag)
があります。LLM_SCOPED_TAG_WITH_STAT
などの統計情報を使うスコープ マクロは、現時点では非推奨であるため使用しないでください。
LLM 内部で使用するすべてのメモリは、プラットフォームにより供給される LLMAlloc
関数と LLMFree
関数によって管理されます。LLM が自身のメモリ使用量をトラックしないように (そして無限再帰呼び出しを生じないように)、LLM では他の方法でアロケーションを行わないようにすることが重要です。
追加の技術的詳細
このセクションでは、LLM を使用する際に知っておくべきさまざまな注意事項や追加情報を示します。
- LLM のオーバーヘッドは 100MB 以上になることがあるため、各コンソールの大きなメモリ モードで実行することを強くお勧めします。
- テスト コンフィグの LLM では統計情報ページを画面に表示しませんが、
.CSV
ファイルには書き出されます。シッピングでは LLM は完全に無効になります。 - アセット タグのトラッキングについてはまだ早期実験段階にあります。