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
PRO
November 30, 2015
Programming
14
39k
Unityにおけるメモリ管理
2015/11/15 Cygames Tech Fes
Cygames
PRO
November 30, 2015
Tweet
Share
More Decks by Cygames
See All by Cygames
【U/Day Tokyo 2025】Cygames流 最新スマートフォンゲームの技術設計 〜『Shadowverse: Worlds Beyond』におけるアーキテクチャ再設計の挑戦~
cygames
PRO
4
2.5k
【CEDEC+KYUSHU2025】学生・若手必見!テクニカルアーティスト 大全 ~仕事・スキル・キャリアパス、TAの「わからない」を徹底解剖~
cygames
PRO
0
380
【TiDB User Day2025】リリース時のアクセス急増をいかにしてノーメンテで乗り越えたか 〜『Shadowverse: Worlds Beyond』におけるTiDB採用のゲームサーバー設計〜
cygames
PRO
1
2.1k
【CEDEC2025】『Shadowverse: Worlds Beyond』二度目のDCG開発でゲームをリデザインする~遊びやすさと競技性の両立~
cygames
PRO
2
620
【CEDEC2025】大規模言語モデルを活用したゲーム内会話パートのスクリプト作成支援への取り組み
cygames
PRO
2
1.8k
【CEDEC2025】現場を理解して実現!ゲーム開発を効率化するWebサービスの開発と、利用促進のための継続的な改善
cygames
PRO
0
1.4k
【CEDEC2025】ブランド力アップのためのコンテンツマーケティング~ゲーム会社における情報資産の活かし方~
cygames
PRO
0
1.4k
【CEDEC2025】『ウマ娘 プリティーダービー』における映像制作のさらなる高品質化へ!~ 豊富な素材出力と制作フローの改善を実現するツールについて~
cygames
PRO
0
490
【CEDEC2025】LLMを活用したゲーム開発支援と、生成AIの利活用を進める組織的な取り組み
cygames
PRO
1
3.9k
Other Decks in Programming
See All in Programming
Cell-Based Architecture
larchanjo
0
150
実はマルチモーダルだった。ブラウザの組み込みAI🧠でWebの未来を感じてみよう #jsfes #gemini
n0bisuke2
3
1.3k
SwiftUIで本格音ゲー実装してみた
hypebeans
0
520
Findy AI+の開発、運用におけるMCP活用事例
starfish719
0
1.8k
안드로이드 9년차 개발자, 프론트엔드 주니어로 커리어 리셋하기
maryang
1
140
「コードは上から下へ読むのが一番」と思った時に、思い出してほしい話
panda728
PRO
39
26k
ZJIT: The Ruby 4 JIT Compiler / Ruby Release 30th Anniversary Party
k0kubun
1
300
令和最新版Android Studioで化石デバイス向けアプリを作る
arkw
0
460
Rubyで鍛える仕組み化プロヂュース力
muryoimpl
0
220
公共交通オープンデータ × モバイルUX 複雑な運行情報を 『直感』に変換する技術
tinykitten
PRO
0
170
gunshi
kazupon
1
120
Denoのセキュリティに関する仕組みの紹介 (toranoana.deno #23)
uki00a
0
180
Featured
See All Featured
[SF Ruby Conf 2025] Rails X
palkan
0
650
Reality Check: Gamification 10 Years Later
codingconduct
0
2k
Believing is Seeing
oripsolob
0
16
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
PRO
196
70k
Fireside Chat
paigeccino
41
3.8k
The World Runs on Bad Software
bkeepers
PRO
72
12k
Product Roadmaps are Hard
iamctodd
PRO
55
12k
Ten Tips & Tricks for a 🌱 transition
stuffmc
0
37
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
34
2.6k
Prompt Engineering for Job Search
mfonobong
0
130
Code Review Best Practice
trishagee
74
19k
How to train your dragon (web standard)
notwaldorf
97
6.5k
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