Help us understand the problem. What is going on with this article?

[UE4] LLM (Low Level Memory Tracker)を使用したメモリトラッキング

More than 1 year has passed since last update.

1. はじめに

 Low Level Memory Tracker(LLM)はメモリの使用状況を追跡するツールです。LLMは4.18から実装されるツールの1つで、UE4のアプリケーションとOSによって割り当てられるすべてのメモリを記録します。
 本記事では4.21.1にて確認しています。

2. 注意点

 事前に認識しておくべきいくつかの注意点があります。

・Editor起動時には不要な情報を含むためパッケージやクック済のゲームで計測する必要があります
  (各プラットフォームで正確にメモリをトラッキングするためにも端末上で計測できるのが望ましい)
・カテゴリ単位でメモリをトラッキングすることができますが、詳細なリーク箇所を特定することはできません
・カテゴリ単位でメモリの占有率を計測できますが、Miscなど精度や定義が曖昧になる部分が含まれます

3. 使い方

 まずは単純にLLMを有効にして、Statsコマンドでメモリ使用量を確認する手順を記載します。

3.1. 起動と確認

・EditorからStandaloneで利用する場合
引数に"-LLM"を付与してStandalone起動するだけです。
2018-12-18_03h22_33.png
・Package Gameで利用する場合
パッケージを作成した後、引数に"-LLM"を付与して起動するだけです。
2018-12-18_03h26_00.png
・Cooked Gameで利用する場合
引数に"-LLM"を付与して起動するだけです。以下はProjectのプロパティから指定するケースです。
2018-12-18_03h28_22.png
もしUnrealVSをインストールしている場合は、画面上部から指定することができます。
2018-12-18_03h27_42.png

 うまくいけば"stat llm""stat llmfull"コマンドを入力するとリストを表示することができます。LLMの起動時の引数が渡せていない場合では統計情報が全て0MBで表示されることがあります。
2018-12-18_03h32_20.png
 起動引数に"-LLM"、statsの表示に"stat llm"を使用しましたが、次の項では他に利用可能な引数やコマンドを説明します。

3.2. Option

 LLMで利用可能な引数・コマンドは以下の通りです。

引数 機能
-LLM LLMを有効にして起動します
-NOLLM LLMを無効にして起動します
(Defaultでは無効で起動します)
-LLMCSV Tag付けされた情報を.csvに記録します。
saved/profiling/llm/ 以下に出力されます
-LLMTAGSETS Tag情報を記録/表示することを許可します
※実験的機能
コマンド 機能
stat LLM Tag付けされた使用中のメモリを表示します
stat LLMFull Tag付けの有無に関わらず全てのメモリを表示します
stat LLMOveread LLM自身で使用しているメモリ情報を表示します
stat LLMPlatform OSの情報を含むメモリ情報を表示します
LLM.LLMWriteInterval .csvに出力する周期を指定して変更できます (Default:5秒)

 LLMTAGSETSは実験的な機能ですが、以下のマクロを有効にすることでAsset単位での情報を出力できます。
(ただしcsvの出力が正しく実施できない問題があります)

\Engine\Source\Runtime\Core\Public\HAL\LowLevelMemTracker.h
    // using asset tagging requires a significantly higher number of per-thread tags, so make it optional
    // even if this is on, we still need to run with -llmtagset=assets because of the shear number of stat ids it makes
    #define LLM_ALLOW_ASSETS_TAGS 1

上記の定義を追加した後、Assetsを以下のように追加すると有効になります。

-llmtagsets="Assets"

2018-12-18_12h30_51.png

Class単位で表示する場合は、AssetClassesを引数とすることで以下のようなClass単位での出力が得られます。

-llmtagsets="AssetClasses"

2018-12-18_12h53_32.png

4. トラッキングメモリ

 LLMでトラッキングする際に割り当てられるタグや、トラッキングしたメモリからの解析に関する情報について説明します。

4.1. タグ

 以下にLLMでトラッキングするタグの一覧を示します。ここで表示する内容はLLMのstatsで表示する内容や.csvファイルとして出力する内容に含まれます。また、プラットフォームでは固有のタグを持つものも存在しますが、それらの内容については割愛しています。

タグ 概要
Untagged タグ付けされていないメモリ
Total Applicationが使用している総メモリ
Untracked 未トラッキング総メモリ
OS込みで利用可能なメモリを示します
Tracked Total LLMでトラッキングしている総メモリ
全てのタグ付けされたメモリの総量を示します
FMalloc 仮想メモリとしてトラッキングしているメモリ
MallocBinned2/ページングキャッシュの総量を示します
FMalloc Unused 仮想メモリで未トラッキングのメモリ
ThreadStack WinThreadで確保されたメモリ
Windowsのみトラッキングします
Program Size プログラムのみで確保されたメモリ
OOM Backup Pool OOMのバックアッププールで確保するメモリ
特定のプラットフォームのみトラッキングします
GenericPlatformMallocCrash 事前割り当てメモリとして確保するメモリ
Engine Misc 他のカテゴリでトラッキングされないメモリ
ActorのEventやEngineLoopで確保されるメモリなど定義が曖昧なものが含まれます
TaskGraph Misc Tasks 他のカテゴリでトラッキングされないTaskGraphで確保されるメモリ
Audio Audio関連のメモリ
SoundWave/StreamingAudio/AudioThreadなどのリソースを含みます
FName FNameで確保されているメモリ
Networking Network関連のメモリ
ReplocationLayoutやNetDriverなどを含みます
Meshes Mesh関連のメモリ
IndexBuffer/VertexBufferで確保するものを含みます
Stats Stats関連のメモリ
デバッグ時の計測や描画によるStatsで確保するものを含みます
Shaders Shader関連のメモリ
GeometryShaderやPixelShaderなど全てのShaderStageで確保するものを含みます
Textures Texture関連のメモリ
Texture2D/Texture3D/Mipmapで確保するメモリを含みます
Render Targets RenderTarget関連のメモリ
RenderTarget/Viewportで確保するメモリを含みます
RHI Misc 分類されないRHI関連のメモリ
RenderThread/RHIThreadで確保するメモリを含みます
PhysX TriMesh PhysXで確保するTriangleMesh関連のメモリ
PhysX ConvexMesh PhysXで確保するConvexMesh関連のメモリ
AsyncLoading 非同期ロード時に確保するメモリ
UObject UObject関連のメモリ
UObjectを継承したクラスおよびプロパティなどシリアライズされるものを含みます
Animation Animation関連のメモリ
AnimationAsset/AnimBP/MorphTargetのアセットやシリアライズデータを含みます
StaticMesh StaticMesh関連のメモリ
StaticMeshと関連するプロパティを含みますがMesh自体のデータは含みません
Materials Material関連のメモリ
Material/MaterialInstanceのアセットやシリアライズデータを含みます
Particles Particle関連のメモリ
ParticleComponentで利用中のアセットやシリアライズデータを含みます
GC GC関連のメモリ
GC実行時(到達可能チェック)処理中に確保されるメモリを含みます
UI UI関連のメモリ
Widget/Slate/TextureAtlasを含みます
PhysX PhysXに投入されるメモリ
PhysXが確保するEngine側の内部的なメモリを含みます
EnginePreInit EngineがPreInitフェーズで確保するメモリ
FEngineLoop::Init()のみトラッキングします
EngineInit EngineがInitフェーズで確保するメモリ
FEngineLoop::Init()のみトラッキングします
Rendering Thread RenderingThreadのメインループで確保するメモリ
LoadMap Misc Mapロード時に確保するメモリ
UEngine::LoadMap()をトラッキングします
StreamingManager StreamingManager関連のメモリ
リソースロード時に確保するメモリをトラッキングします
Graphics プラットフォームのGraphics関連のメモリ
D3D11/D3D12で確保するTexture/Statsなどメモリをトラッキングします
FileSystem FileSystem関連のメモリ
ファイルアクセス時のメモリをトラッキングします

4.2. メモリの推移とリークチェック

 ゲームを長時間稼働させた場合メモリーリークが発生していると特定のタグが増加し続けている傾向がみられるかもしれません。以下は意図的にCharacterを解放させない状態をキャプチャした図ですが、Characterは複数のタグに含まれる要素を持っているため、複数のタグで増加していることが確認できます。このように、長時間でのタグの変化をチェックしてもしリークの傾向がみられる場合は、増加しているタグの箇所を中心に、特定のタグを追加したり、調整することでリークの箇所を特定することができます。
2018-12-18_15h42_11.png

 しかしながら、注意点で記載したようにLLMだけではどこでリークが発生しているかを特定するのは難しいかもしれません。LLMではある程度の傾向を把握し、どのオブジェクトでリークが発生しているかはmemreportを使用したり、どのモジュールでリークしているかはプロファイラーを使用することで、より効率的にリークのポイントを探しだせることに繋がります。

5. その他

強制的にLLMを有効にするためのマクロ
以下の定義を有効にすることで、-LLMを付与せずともLLMの実行を強制します。

\Engine\Source\Runtime\Core\Public\HAL\LowLevelMemTracker.h
    // when set to 1, forces LLM to be enabled without having to parse the command line.
#ifndef LLM_AUTO_ENABLE
    #define LLM_AUTO_ENABLE 1
#endif

Test構成でLLMを有効にするためのマクロ
以下の定義を有効にすることで、Test構成においてもLLMの実行を有効にすることができます。

\Engine\Source\Runtime\Core\Public\HAL\LowLevelMemTracker.h
    #define ALLOW_LOW_LEVEL_MEM_TRACKER_IN_TEST 1

6. まとめ

 メモリリークやメモリに関する検証はアセットやプログラムが揃った終盤に実施することが多いかと思います。しかしながら開発の終盤でもし問題が発覚した場合、大きな変更やアセットの修正を行う時間も限られるため、メモリに関する問題も出来るだけ早めに把握して対応できるのが望ましいです。LLMは容易利用することができるため、開発の中盤などから自動テスト等で検証することをワークフローとして組み込むことで、早期に問題を発見することができます。また、アセットに関してもメモリバジェットを考慮するようになり、以降の作業において手戻りが少なくなるため、開発の全体を俯瞰して見ても非常に便利なツールの1つです。

donbutsu17
主にUnreal Engineに関する記事を書きます。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした