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
9.1k
【CEDEC+KYUSHU2025】学生・若手必見!テクニカルアーティスト 大全 ~仕事・スキル・キャリアパス、TAの「わからない」を徹底解剖~
cygames
PRO
0
990
【TiDB User Day2025】リリース時のアクセス急増をいかにしてノーメンテで乗り越えたか 〜『Shadowverse: Worlds Beyond』におけるTiDB採用のゲームサーバー設計〜
cygames
PRO
1
2.4k
【CEDEC2025】『Shadowverse: Worlds Beyond』二度目のDCG開発でゲームをリデザインする~遊びやすさと競技性の両立~
cygames
PRO
2
690
【CEDEC2025】大規模言語モデルを活用したゲーム内会話パートのスクリプト作成支援への取り組み
cygames
PRO
2
2.2k
【CEDEC2025】現場を理解して実現!ゲーム開発を効率化するWebサービスの開発と、利用促進のための継続的な改善
cygames
PRO
0
1.6k
【CEDEC2025】ブランド力アップのためのコンテンツマーケティング~ゲーム会社における情報資産の活かし方~
cygames
PRO
0
1.6k
【CEDEC2025】『ウマ娘 プリティーダービー』における映像制作のさらなる高品質化へ!~ 豊富な素材出力と制作フローの改善を実現するツールについて~
cygames
PRO
0
610
【CEDEC2025】LLMを活用したゲーム開発支援と、生成AIの利活用を進める組織的な取り組み
cygames
PRO
1
4.6k
Other Decks in Programming
See All in Programming
クライアントワークでSREをするということ。あるいは事業会社におけるSREと同じこと・違うこと
nnaka2992
1
350
RubyとGoでゼロから作る証券システム: 高信頼性が求められるシステムのコードの外側にある設計と運用のリアル
free_world21
0
310
「やめとこ」がなくなった — 1月にZennを始めて22本書いた AI共創開発のリアル
atani14
0
400
Fundamentals of Software Engineering In the Age of AI
therealdanvega
2
260
「接続」—パフォーマンスチューニングの最後の一手 〜点と点を結ぶ、その一瞬のために〜
kentaroutakeda
2
870
Rで始めるML・LLM活用入門
wakamatsu_takumu
0
190
The Past, Present, and Future of Enterprise Java
ivargrimstad
0
750
Codexに役割を持たせる 他のAIエージェントと組み合わせる実務Tips
o8n
4
1.4k
最初からAWS CDKで技術検証してもいいんじゃない?
akihisaikeda
4
160
CDIの誤解しがちな仕様とその対処TIPS
futokiyo
0
220
コーディングルールの鮮度を保ちたい / keep-fresh-go-internal-conventions
handlename
0
210
CSC307 Lecture 14
javiergs
PRO
0
480
Featured
See All Featured
How to Grow Your eCommerce with AI & Automation
katarinadahlin
PRO
1
150
Building a A Zero-Code AI SEO Workflow
portentint
PRO
0
400
Impact Scores and Hybrid Strategies: The future of link building
tamaranovitovic
0
230
ReactJS: Keep Simple. Everything can be a component!
pedronauck
666
130k
A better future with KSS
kneath
240
18k
Chasing Engaging Ingredients in Design
codingconduct
0
140
Visual Storytelling: How to be a Superhuman Communicator
reverentgeek
2
470
The Invisible Side of Design
smashingmag
302
51k
個人開発の失敗を避けるイケてる考え方 / tips for indie hackers
panda_program
122
21k
Skip the Path - Find Your Career Trail
mkilby
1
85
Large-scale JavaScript Application Architecture
addyosmani
515
110k
A Soul's Torment
seathinner
5
2.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