unityでいってみよう!

unityがチョットワカル位の人のブログ

Memory Profilerの見方 Simple View編

 

はじめに

Memory Profierで計測をしていると、様々な情報を表示してくれますが、Unityの公式ドキュメントでは、ふわっとした内容が記載されており、正直なんとなくしか理解出来ていない部分が多々あると思います。

Profileをより意味のあるものにする為には、それが何を意味しているのかを正確に知る必要がありそうです。

  

2つのMemory Profiler

実はUnityにはMemory Profilerと呼ばれているものが2種類存在します。(ややこしい)

ひとつは、Package Managerからインストールすることが出来るMemory Profiler、もうひとつはUnity Profilerの1機能であるMemory Profilerです。

今回は後者のUnity Profilerの1機能であるMemory Profilerに関する内容です。

 

 PackageManagerからインストールMemory Profiler

docs.unity3d.com

 

EditorにBuildinされているMemory Profiler

docs.unity3d.com

 

Simple View

そもそもSimple Viewとは何かという点についてですが、Memory ProfilerにはSimpleとDetaile2種類があります。

使い分けとしては、先ずSimple Viewで全体像を把握して、その後Detailed Viewで絞り込んでいくような形になると思います。

今回はその2種類のViewの内、Simple Viewに関する考察です。

 

Simple View

https://docs.unity3d.com/ja/2018.4/uploads/Main/ProfilerMemorySimple.png

Detailed View

https://docs.unity3d.com/ja/2018.4/uploads/Main/ProfilerMemoryDetailed.png

  

前提条件

Editor上で実行しているものを計測すると、Editor上で確保しているものを重複して計測してしまう為、正しい値が取れません。

必ず実機で実行しているアプリケーションを計測するようにしましょう。

  

Used TotalとReserved Total

Unityのドキュメントによると

Unity は OS があまり頻繁にメモリを要求することを防ぐため、アロケーションのためにメモリプールを確保します。確保したメモリは Reserved として、使用されたメモリとともに表示されます。

 これはが意味するところは、Unityは内部でMemoryManager的な何かを持っており、事前にMemoryManagerが各カテゴリ毎にOSからMemoryをガッツリ(Playerの場合4MB、Editorの場合16MB)確保し、各処理においてメモリを確保する際に、OSから直接確保するのではなく、各カテゴリ毎に要求があったら事前に確保していた領域から割当て、不足したらその時に改めてOSから確保し直すということを意味していると思われます。

Reserved Total : UnityがOSから確保している仮想メモリのサイズです。Scriptからは Profiler.GetTotalReservedMemoryLongで求めることが出来ます。

 

 Used Total : Reservedの内実際に使用している仮想メモリのサイズです。

 

また、各値から合計を求めてもTotalと微妙に異なります。これはProfilerがトラッキングしていないものがある為です。

 ユーザーが観測している瞬間においては常に

 Reserved > Used 

 が成り立ち、UsedがReservedを超える瞬間にUnityはOSからメモリを新たに再確保を行います。つまり、実際にAllocateしているサイズはReservedであり、どちらかというとReserved側に注意を払う必要がありそうです。

また、ReservedとUsedの値がかけ離れている場合、Memoryの使用効率が良くないということを表しているのでプログラムを見直す必要がありそうです。

 

Unity

ドキュメントには次のように記載されています。

Unity のネイティブコードへのメモリ割り当て量

ネイティブコードへのメモリの割当とは、アプリケーションがOSから割り当てられた仮想メモリを指していると考えられます。UnityPlayerが管理している領域だと捉えるのがよいでしょう。

例えば、巨大なオブジェクト(例えばTexture2D)はMonoではなくUnityにアロケートされます。(読み書き禁止になっているTextureはCPUからGPUへ転送後はUnityから削除されるのでややこしいのですが。)

Unityにはトラッキングされていない領域も含まれています。

 

Unity≒ Profiler.GetTotalAllocatedMemoryLong()+Profilerがトラッキングしていないメモリ-(Profiler + FMOD + Video)

 

Profilerがトラッキングしていないメモリとは3rdパーティのライブラリやOSがAllocateするメモリです。

 

Mono

.NETのバーチャルマシンに割り当てられるメモリで、いわゆるMonoHeapのメモリブロックのサイズです。

C#(Unity Scriptも)からAllocateされるものはこちらに含まれまれ、Garbage Collecterによって管理されています。

Unityのモジュールの中にもC#で記載されているもの(uGUI等)があるので注意が必要です。

 

GfxDriver 

ドライバが Texture、レンダリングのターゲット、Shader、Mesh データに使用している推定メモリ量

ドライバとはOpenELGSやValukanといったGraphicAPIとUnityの中間層に位置するものだと思われますので、GfxDirverの値はGPU用に確保した領域を指しています。

おそらくGPUの確保先の物理メモリがハード(Diver?)によってVRAMであったり、メインメモリであったりと異なるので分けているのだと思います。

Texture、レンダーターゲット、Shader、Meshといった描画に関係のあるオブジェクトがGfxDriver側で確保します。なお、Monoでも書きましたが、TextureやMeshといったは通常一旦Unity側で取られたあと、GfxDriver側へ移動した後、Unityから削除されます。しかしながら、そのオブジェクトが編集可能すなわちRead/WriteがEnableな場合、Unity側とGfxDriver側の両方に確保されので注意が必要です。

 

FMOD

FMOD(Audio再生)に使用しているメモリ。単発とストリーム再生の合計が表示されています。

FMOD以外の外部のミドルウエアを使用してAudio再生を行っている場合は0となります。

 

Video

動画再生に使用されるメモリ。

 

 Textures・Meshes・Materials・AnimationClips・AudioClips

MemoryManagerがAllocateしたオブジェクトの数とオブジェクトサイズの合計を表示しています。尚、UsedとReserved では確保した仮想メモリのサイズでこちらはオブジェクトのサイズを表示している為、ReservedとUsed側の方が大きくなっています。

 

Assets

SceneやResource(Buiteinを含む)やAssetBundleからロードされたAssetの総数です。Detail ViewのAssetsに該当すると思われますが、微妙に数が一致しません。

 

GameObjects in Scene

Scene(Hierarchy)上に存在するGameObjectの数です。

Scene自体もカウントしてるようです。

  

Total Objects in Scene

GameObject in SceneにDetail ViewのSceneMemoryの個数を加算した値です。 

 

Total Object Count

生成されているObject(GameObjectではない)の総数です。

Detail Viewで表示されている、Assets、Scene Memory 、Not Savedのそれぞれの個数の合計になります。(Othersは含まれていないことに注意して下さい。)

 

Total System Memory Usage

Unity2018以降ではプラットフォームがAndroidの場合においてもこの値が表示されるようになりましたが、正しい値を返していません。Unity2018.4.19、Unity2019.3.10にて確認を行いました。ご注意下さい。

検証の結果、Androidでは/proc/meminfo に記載されているMemTotalからMemFreeを引いた値を表示している模様です。これは端末が積んでいる物理メモリから使用されていないメモリを引いた数値であり、アプリケーションが使用している仮想メモリの合計とは異なります。

 

 UnityPlayer(プロセス)が使用している仮想メモリの合計です。

これにはProfilerに表示されていないものも含めて全てのものが含まれます。

OutofMemoryはこの値で決まると思われます。

Reservedの値はそれほどでもないのに何故かOutOfMemoryが発生するという場合はこちらに注目してみて下さい。

 

Total System Memory Usage = Reserved Total + 実行ファイルのイメージ(コードとデータ)

 

WindowsにおけるPROSESS_MEMORY_COUNTERS_EXのPrivateUsage に該当します。

docs.microsoft.com

 

 

Total System Memory Usage > Reserved Total > Used Total の関係が成り立ちますが、Editorで実行した場合はこの関係が成り立たないことがあります。

Editorはあくまでも雰囲気を掴むレベルのものです。正確なProfileは必ず実行で行うようにしましう。

  

GC Allocations per Frame

1フレーム辺りに発生しているMono側のAllocateの発生回数とサイズの合計です。

 

  

参考情報

www.slideshare.net

 

docs.unity3d.com

 

Memory profiling question: "Used Total" vs "Total System Memory Usage"

https://forum.unity.com/threads/memory-profiling-question-used-total-vs-total-system-memory-usage.462919/