動的に生成したTextureとSpriteはしっかり管理しよう!
お久しぶりです。
随分長いことブログを放置していました。
さて今回はアプリ開発やゲーム開発で頭を悩ませるメモリリークについてです。
メモリリークとは、プログラムのゴミがどんどん蓄積されてメモリが「もう満帆無理っす!」ということでアプリが落ちてしまうバグです。
詳細な説明はWiki先生に記載されています。
私が経験したメモリリークの中で最近苦労したことは、Texture2DとSpriteを動的に生成する処理は、コンポーネントしているGameObjectがDestroy(破棄)されてもTexture2DとSpriteが残ってしまうということです。
public class CreateTexture : MonoBehaviour { public int m_createCount = 100; private List<Texture2D> texture2dList = new List<Texture2D>(); private List<Sprite> spriteList = new List<Sprite>(); // Use this for initialization void Start () { for(int i =0; i < m_createCount; i++) { Texture2D texture2D = new Texture2D(1000, 1000); Sprite sprite = Sprite.Create(texture2D, new Rect(0.0f, 0.0f, 1000, 1000), Vector2.zero); texture2dList.Add(texture2D); spriteList.Add(sprite); } DestroyTexture2D(); } private void DestroyTexture2D() { Destroy(this.gameObject); } }
上記のソースコードを実行させてProfilerのMemoryのName>Scene Memorで確認すると…
何と生成したTexture2DとSpriteが残っているではないか!?
では処理を少し修正した状態でProfilerを確認してみましょう。
public class CreateTexture : MonoBehaviour { public int m_createCount = 100; private List<Texture2D> texture2dList = new List<Texture2D>(); private List<Sprite> spriteList = new List<Sprite>(); // Use this for initialization void Start () { for(int i =0; i < m_createCount; i++) { Texture2D texture2D = new Texture2D(1000, 1000); Sprite sprite = Sprite.Create(texture2D, new Rect(0.0f, 0.0f, 1000, 1000), Vector2.zero); texture2dList.Add(texture2D); spriteList.Add(sprite); } DestroyTexture2D(); } private void DestroyTexture2D() { foreach(var tex in texture2dList) { Destroy(tex); } foreach(var spr in spriteList) { Destroy(spr); } Destroy(this.gameObject); } }
今度はTexture2DとSpriteが消えている事を確認することができましたね。
どうやらUnityの仕様上、GameObjectが破棄されても生成されたTexture2DとSpriteが残ってしまうようです。
これは知らないと修正作業が少しめんどくさくなりますね。
後、Resources.UnloadUnusedAssetsで使わなくなったAsset(今回で言うところのTexture2DとSprite)を解放することができます。
ただしResources.UnloadUnusedAssetsは多様すると良くないらしいです…。
public class CreateTexture : MonoBehaviour { public int m_createCount = 100; private List<Texture2D> texture2dList = new List<Texture2D>(); private List<Sprite> spriteList = new List<Sprite>(); // Use this for initialization void Start () { for(int i =0; i < m_createCount; i++) { Texture2D texture2D = new Texture2D(1000, 1000); Sprite sprite = Sprite.Create(texture2D, new Rect(0.0f, 0.0f, 1000, 1000), Vector2.zero); texture2dList.Add(texture2D); spriteList.Add(sprite); } DestroyTexture2D(); } private void DestroyTexture2D() { Destroy(this.gameObject); } private void OnDestroy() { Resources.UnloadUnusedAssets(); } }
なので皆さん、くれぐれもAssetの管理には気をつけましょう!
※参考サイトは以下になります。