Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Unityにおけるメモリ管理
Search
Cygames
November 30, 2015
Programming
14
38k
Unityにおけるメモリ管理
2015/11/15 Cygames Tech Fes
Cygames
November 30, 2015
Tweet
Share
More Decks by Cygames
See All by Cygames
『GRANBLUE FANTASY Relink』キャラクターの魅力を支えるリグ・シミュレーション制作事例
cygames
0
410
『GRANBLUE FANTASY: Relink』最高の「没入感」を実現するカットシーン制作手法とそれを支える技術
cygames
1
320
『GRANBLUE FANTASY Relink』ソフトウェアラスタライザによる実践的なオクルージョンカリング
cygames
0
320
高品質なフォトグラメトリデータを取得するためのハードウェア&ソフトウェア開発
cygames
0
1.1k
AIを活用した柔軟かつ効率的な社内リソース検索への取り組み
cygames
0
980
『GRANBLUE FANTASY: Relink』開発からリリースまでを支えたCI/CDの取り組み
cygames
0
240
『GRANBLUE FANTASY: Relink』専任エンジニアチームで回す大規模開発QAサイクル
cygames
0
260
『GRANBLUE FANTASY: Relink』クオリティと物量の両立に挑戦したフェイシャルアニメーション事例 ~カットシーンからランタイムまで~
cygames
0
280
『GRANBLUE FANTASY: Relink』キャラクターの個性にlinkした効果音表現
cygames
0
130
Other Decks in Programming
See All in Programming
よくできたテンプレート言語として TypeScript + JSX を利用する試み / Using TypeScript + JSX outside of Web Frontend #TSKaigiKansai
izumin5210
6
1.7k
3 Effective Rules for Using Signals in Angular
manfredsteyer
PRO
1
100
エンジニアとして関わる要件と仕様(公開用)
murabayashi
0
280
【Kaigi on Rails 2024】YOUTRUST スポンサーLT
krpk1900
1
330
Webの技術スタックで マルチプラットフォームアプリ開発を可能にするElixirDesktopの紹介
thehaigo
2
1k
AI時代におけるSRE、 あるいはエンジニアの生存戦略
pyama86
6
1.1k
CSC509 Lecture 12
javiergs
PRO
0
160
Pinia Colada が実現するスマートな非同期処理
naokihaba
4
220
Kaigi on Rails 2024 〜運営の裏側〜
krpk1900
1
190
Jakarta Concurrencyによる並行処理プログラミングの始め方 (JJUG CCC 2024 Fall)
tnagao7
1
290
アジャイルを支えるテストアーキテクチャ設計/Test Architecting for Agile
goyoki
9
3.3k
ECS Service Connectのこれまでのアップデートと今後のRoadmapを見てみる
tkikuc
2
250
Featured
See All Featured
10 Git Anti Patterns You Should be Aware of
lemiorhan
654
59k
Stop Working from a Prison Cell
hatefulcrawdad
267
20k
Navigating Team Friction
lara
183
14k
Faster Mobile Websites
deanohume
305
30k
Put a Button on it: Removing Barriers to Going Fast.
kastner
59
3.5k
Become a Pro
speakerdeck
PRO
25
5k
The Psychology of Web Performance [Beyond Tellerrand 2023]
tammyeverts
44
2.2k
Java REST API Framework Comparison - PWX 2021
mraible
PRO
28
8.2k
A better future with KSS
kneath
238
17k
Designing for humans not robots
tammielis
250
25k
Dealing with People You Can't Stand - Big Design 2015
cassininazir
364
24k
The Cost Of JavaScript in 2023
addyosmani
45
6.7k
Transcript
None
自己紹介 $POGJEFOUJBM $PQZSJHIU $ZHBNFT *OD "MM3JHIUT3FTFSWFE • 高原 光示
• Cygamesでエンジニアリーダーをやっています • 以前はPC向けのオンラインゲームを作ってい ました • 3D・リアルタイム通信・セキュリティが得意
今日のおはなし $POGJEFOUJBM $PQZSJHIU $ZHBNFT *OD "MM3JHIUT3FTFSWFE • Unityのメモリについておさらい •
メモリリーク事例の紹介 • メモリリークの探し方 • まとめ
なぜメモリの管理が必要か? $POGJEFOUJBM $PQZSJHIU $ZHBNFT *OD "MM3JHIUT3FTFSWFE • メモリを無駄に使うとアプリのクラッシュに繋が る
• クラッシュしない場合でも、アプリをバックグラ ウンドにした際にOSからタスクキルされやすく なる
Unityのメモリの種類 $POGJEFOUJBM $PQZSJHIU $ZHBNFT *OD "MM3JHIUT3FTFSWFE • Mono管理 •
Unity管理
Mono管理のメモリ $POGJEFOUJBM $PQZSJHIU $ZHBNFT *OD "MM3JHIUT3FTFSWFE • Stack –
Intやfloatなどの値型 – Structやenum • Heap – Classやdelegateなどの参照型 – 参照されなくなったインスタンスはGC時で解放 – メモリが確保できなくなると自動的にメモリ領域を 拡張する • ピーク使用量を抑える必要がある • ファイルIOなどで無駄に確保しすぎると危険
参照されないとは? $POGJEFOUJBM $PQZSJHIU $ZHBNFT *OD "MM3JHIUT3FTFSWFE • インスタンスを変数に格納すると「参照」してる ことになる
• Unityの場合、シーン上のオブジェクトか静的 フィールドから変数をたどっていくことができる 場合「参照」されている
Unity管理のメモリ $POGJEFOUJBM $PQZSJHIU $ZHBNFT *OD "MM3JHIUT3FTFSWFE • TextureやMesh等のアセット類 •
Resources.Load • AssetBundle.LoadAsset • Resources.UnloadAsset • Resources.UnloadUnusedAssets
Resources.UnloadUnusedAssets $POGJEFOUJBM $PQZSJHIU $ZHBNFT *OD "MM3JHIUT3FTFSWFE • アプリから参照されていないリソースを破棄 •
シーン遷移時にも同等の処理が行われる • 個別のリソースをUnloadするのは大変面倒な ので、 基本的にはこの関数を使ってリソースを管理す ることになる
メモリリーク事例の紹介 (Unity5.2.1) $POGJEFOUJBM $PQZSJHIU $ZHBNFT *OD "MM3JHIUT3FTFSWFE
リソースが解放されない例1 (1/3) public class AssetLoader : MonoBehaviour { Object reference;
void Awake() { // リソースをLoadして参照を保持するだけ reference = Resources.Load("texture"); } } $POGJEFOUJBM $PQZSJHIU $ZHBNFT *OD "MM3JHIUT3FTFSWFE
リソースが解放されない例1 (2/3) public class Sample1 : MonoBehaviour { public AssetLoader
obj; IEnumerator Start() { Destroy(obj); // 実際にDestroyされるのはフレームの最後なので1フレーム待つ yield return 0; Debug.Log(obj); // => null Resources.UnloadUnusedAssets(); // アセットは解放されない! } } $POGJEFOUJBM $PQZSJHIU $ZHBNFT *OD "MM3JHIUT3FTFSWFE
リソースが解放されない例1 (3/3) public class Sample1 : MonoBehaviour { public AssetLoader
obj; IEnumerator Start() { Destroy(obj); // 実際にDestroyされるのはフレームの最後なので1フレーム待つ yield return 0; Debug.Log(obj); // => null obj = null; Resources.UnloadUnusedAssets(); // OK. } } $POGJEFOUJBM $PQZSJHIU $ZHBNFT *OD "MM3JHIUT3FTFSWFE
リソースが解放されない例2 (1/4) public class AssetLoader : MonoBehaviour { Object reference;
void Awake() { reference = Resources.Load("texture"); } public void Log() { Debug.Log("hoge"); } } $POGJEFOUJBM $PQZSJHIU $ZHBNFT *OD "MM3JHIUT3FTFSWFE
リソースが解放されない例2 (2/4) public class Sample2 : MonoBehaviour { public AssetLoader
obj; public System.Action action { get; set; } void Start() { action = obj.Log; Destroy(obj); obj = null; Resources.UnloadUnusedAssets(); // アセットは解放されない! } } $POGJEFOUJBM $PQZSJHIU $ZHBNFT *OD "MM3JHIUT3FTFSWFE
リソースが解放されない例2 (3/4) public class Sample2 : MonoBehaviour { public AssetLoader
obj; public System.Action action { get; set; } void Start() { action = obj.Log; Destroy(obj); obj = null; action = null; Resources.UnloadUnusedAssets(); // OK. } } $POGJEFOUJBM $PQZSJHIU $ZHBNFT *OD "MM3JHIUT3FTFSWFE
リソースが解放されない例2 (4/4) public class Sample2 : MonoBehaviour { public AssetLoader
obj; public System.Action action { get; set; } void Start() { // lambdaを渡すと参照されていないことになる action = () => obj.Log(); Destroy(obj); obj = null; Resources.UnloadUnusedAssets(); // OK. } } $POGJEFOUJBM $PQZSJHIU $ZHBNFT *OD "MM3JHIUT3FTFSWFE
リソースが解放されない例3 (1/3) public class SingletonMonoBehaviour <T> : MonoBehaviour where T
: MonoBehaviour { private static T instance = null; public static T Instance { get { if (instance == null) { instance = FindObjectOfType<T>(); } return instance; } } void Awake() { if (instance != null && instance != this) { Destroy(gameObject); return; } instance = this as T; } } $POGJEFOUJBM $PQZSJHIU $ZHBNFT *OD "MM3JHIUT3FTFSWFE
リソースが解放されない例3 (2/3) public class Scene1 : SingletonMonoBehaviour<Scene1> { Object reference;
void Start() { reference = Resources.Load("texture"); // DontDestroyOnLoadを指定していないので、 // リソースは破棄されるはず・・・ Application.LoadLevel("Scene2"); // シーン遷移後にリソースが破棄されていない! } } $POGJEFOUJBM $PQZSJHIU $ZHBNFT *OD "MM3JHIUT3FTFSWFE
リソースが解放されない例3 (3/3) public class SingletonMonoBehaviour<T> : MonoBehaviour where T :
MonoBehaviour { // 省略 // Destroyされる前に参照を外す必要がある void OnDestroy() { if (instance == this) instance = null; } } $POGJEFOUJBM $PQZSJHIU $ZHBNFT *OD "MM3JHIUT3FTFSWFE
メモリリークの探し方 $POGJEFOUJBM $PQZSJHIU $ZHBNFT *OD "MM3JHIUT3FTFSWFE
2.Detailedを選択 3.TakeSampleEditorを押す押 したフレームのメモリダンプが 表示される 1.Memoryを選択 $POGJEFOUJBM $PQZSJHIU $ZHBNFT *OD
"MM3JHIUT3FTFSWFE
メモリ上のリソースが意図したも のかどうか確認 参照してるObjectをヒントに 怪しいコードを探す $POGJEFOUJBM $PQZSJHIU $ZHBNFT *OD "MM3JHIUT3FTFSWFE
TIPS $POGJEFOUJBM $PQZSJHIU $ZHBNFT *OD "MM3JHIUT3FTFSWFE • Inspector等でアセットを表示するとリソースが 解放されない
– 調査時に混乱するので、Hierarchyの何もない部 分をクリックしておく • ReferencedByに ManagedStaticReferences()と表示されてる のはstaticなインスタンスからの参照 – 全てのstatic変数を疑わないといけない
まとめ $POGJEFOUJBM $PQZSJHIU $ZHBNFT *OD "MM3JHIUT3FTFSWFE • リソースの管理はシンプルに •
静的変数とdelegateはリークに繋がる事が多 いので要注意 • メモリのダンプをとれるAPIが欲しい • むしろUnityがDestroyされたオブジェクトから は参照されてないことにすれば大体解決する のでは・・・!
ご静聴ありがとうございました $POGJEFOUJBM $PQZSJHIU $ZHBNFT *OD "MM3JHIUT3FTFSWFE