1. はじめに
[検証バージョン:4.23.0]
MemProはC++メモリトラッキングツールで、UE4は4.23からインテグレーションに対応しています。
本記事では MemPro を使用してUE4アプリケーションのメモリトラッキングを行う方法について説明します。
2. MemProの利用にあたって
MemProをUE4で利用する上で、導入を検討する内容としてご参考ください。
2.1. 機能
・LLMタグベースでのメモリをトラッキングします
(UE4でメモリトラッキング時にはLLMタグの指定が必須)
・関数別、タイプ別での追跡機能や差分の検出機能があります
・キャプチャしたデータをエクスポートできます
2.2. メリット
・イテレーションやセットアップのしやすさの点でMalloc Profilerよりも優れています1
・コールツリーの機能を持つためLLMよりもトラッキング精度の面で優れています2
・トラッキング処理のコストも比較的低く、比較的長時間のトラッキングが可能です3
2.3. 注意点
・MemProは有償のツールで、トライアルで30日間無償で利用可能、[MemPro]->[Purchase]から購入可能です
(1マイナーバージョンアップグレードの永久ライセンス:JP¥15,390/1ユーザーライセンス)4
3. MemProで出来ること
以下にMemProツールで出来ることを示します。予め出来ることを把握することで、メモリトラッキングの目的に合致しているかを確認しておくとより効果的です。
3.1. Memory Graph
3.2. Call Tree
3.3. Page View
3.4. Functions
3.5. Types
その他、ツールの使い方はMemPro Users Guideで説明されています。
4. 使い方
1) 準備
MemPro用のトラッキングを有効にするため [Project].Target.cs に以下のように MEMPRO_ENABLED=1 を追加します。以下はWin64のみトラッキングを適用する例です。
public class TP_423Target : TargetRules
{
public TP_423Target(TargetInfo Target) : base(Target)
{
Type = TargetType.Game;
ExtraModuleNames.AddRange( new string[] { "TP_423" } );
// Win64でのみMemProトラッキングを有効にする場合以下を追加
if (Target.Platform == UnrealTargetPlatform.Win64)
{
GlobalDefinitions.Add("MEMPRO_ENABLED=1");
}
}
}
もしエディタで計測を行いたい場合は、プロジェクトではなくエディタのターゲット [Project]Editor.Target.cs に追記してください。以下はその例です。
public class TP530EditorTarget : TargetRules
{
public TP530EditorTarget(TargetInfo Target) : base(Target)
{
Type = TargetType.Editor;
DefaultBuildSettings = BuildSettingsVersion.V4;
// ここから
BuildEnvironment = TargetBuildEnvironment.Unique;
GlobalDefinitions.Add("MEMPRO_ENABLED=1");
// ここまで
ExtraModuleNames.AddRange( new string[] { "TP530" } );
}
}
2) 起動とキャプチャ
メモリのトラッキングにはLLMを利用するため、起動引数として -llm を指定する必要があります。
それから "MemPro.LLMTag [tag]" で追跡するタグを選択し、"MemPro.Enabled 1" でキャプチャを開始できます。キャプチャを終了する場合はアプリケーションを終了すると自動で停止します。MemProのLaunchから起動引数を定義して起動することも可能です。
// [LLM_TAG]を好みの設定に併せてください
-llm -nothreadtimeout -execcmds="MemPro.LLMTag [LLM_TAG]"
以下のケースでは、アプリケーション起動時から全LLMタグのトラッキングを開始します。
-llm -nothreadtimeout -execcmds="MemPro.LLMTag *, MemPro.Enabled 1"
以下のケースでは、StaticMeshのメモリをトラッキングします。このケースでは起動時に有効にするコマンドを含めていないので、 "MemPro.Enabled 1" を任意のタイミングで実行してキャプチャを開始することができます。
-llm -nothreadtimeout -execcmds="MemPro.LLMTag StaticMesh"
ここで指定することが可能なタグは LLM_ENUM_GENERIC_TAGS のリストを参照。以下の例では "Untagged" に該当します。
macro(Untagged, "Untagged", NAME_None, NAME_None, -1)\
キャプチャしたプロファイルは [Project]/Saved/Profiling/MemPro/ に .mempro_dump 形式で保存されます。
5. プロファイルの解析
MemProでキャプチャした結果をMemProで解析する基本的な方法について記載します。
5.1. MemProでのロードと解析
MemProでキャプチャを解析する際にシンボル情報を指定することで関数レベルでの情報を確認することができます。以下にMemProでシンボルファイルのパスを指定する方法を記載していますが、予めパッケージにシンボルファイルを含めておくことでキャプチャにシンボル情報を含めることもできます。
・シンボルファイルのパス指定
・デバッグファイルをパッケージに含める
予めProject SettingsでInclude Debug Filesを有効に設定しておく必要があります。
5.2. リークの解析
1) DiffSnapshotの取得
メモリの増減が発生している箇所の差分情報を取得するため、Memory Graphから差分の範囲を Shift+マウス右クリック(ドラッグ) で選択します。選択後に Show Difference を選択すると差分情報が 「Snapshots」 に保存されます。
2023/10/27時点では、左ドラック選択でも行けるようです。
2) CallGraphから差分のチェック
上記で保存された差分スナップショットを右クリックで選択して 「Call Tree」 を選択します。ロードが完了したら差分に関するCall Treeが表示されるため、どの経路で確保されたメモリが残存しているかを確認してリーク箇所を特定します。下の図は「キーを入力した時にCharacterをSpawnした際のメモリ増加箇所」をキャプチャしたものです。APlayerController::ProcessPlayerInputでの入力をトリガに、UWorld::SpawnActorが実行されて、最終的にSkeletalMeshComponentのPhysicsからメモリが確保されていることが分かります。
(※クリックで拡大)
5.3. プロファイル時の注意点
・全LLMタグを指定することで全てのメモリをトラッキングできますがトラッキング量も多くなります
・モバイルなどでキャプチャする場合はLLMタグを指定することをお勧めします
(予めどのLLMタグでリークが発生しているかを特定しておく必要があります)
6. まとめ
UE4アプリケーションに関するメモリトラッキングの手段は他にも様々な方法(stat memoryコマンド、Memreportコマンド, Malloc Profiler, LLM, 専用のトラッキングツール等)がありますが、MemProは他のツールとしても非常に使いやすいので5是非お試しください。
[関連記事]
公式ブログ:デバッグとメモリーの最適化
公式ブログ:アンリアル エンジン 4 のメモリリーク対策
Qiita:[UE4] LLM (Low Level Memory Tracker)を使用したメモリトラッキング
Qiita:[UE4] Malloc Profiler/Memory Profiler2を使用したメモリトラッキング