渋谷ほととぎす通信

完全趣味でやってる技術メモ。※所属団体とは一切関係がありません。

Unity RenderTextureのメモリ確保と解放タイミングの落とし穴


RenderTextureを動的にスクリプトから生成して、Blitしてごにょにょするというフローの中で、どのタイミングでメモリが確保され、いつ解放されるのか確認したいと思います。

メモリのプロファイルということでUnity製MemoryProfilerを使います。
本環境はUnity2018.3.0f2なので、PackageManagerから0.1.0-preview.3をダウンロードします。

f:id:esakun:20181227114641p:plain

メモリ確保タイミングの確認

メモリが確保される予測タイミングは、

  • RenderTextureをnewして生成した時
  • RenderTextureにBlitしてピクセルを書き込んだ時

この2パターンかなと思っています。
とりあえずEditor上でプロファイリングしていきます。

RenderTextureをnewして生成する

実行前 実行後
f:id:esakun:20181227115425p:plain:w300 f:id:esakun:20181227115350p:plain:w300
93.4MB 1.59GB

※実行前に存在するRenderTexutureはUnityEditorのシーンView、GameView表示のためにデフォルトで用意されているものです

わかりやすくするためにW2048×H2048pxのRenderTextureを50枚生成した結果がコチラです。 この結果から


「RenderTextureをnewして生成した時」
※後述しますがこれは間違いです


がメモリ確保タイミングということだとわかります。

ただし、これはあくまでUnityEditor上でのプロファイリングなので実機上で確認してみます。

検証環境

  • macOS 10.13.6
  • Xcode 10.1
  • iPhone6s iOS12.1

実機からUnityのMemoryProfilerに接続して同様に確認してみます。

実行前 実行後
f:id:esakun:20181227120720p:plain:w300 f:id:esakun:20181227120819p:plain:w300
0MB 1.56GB

予想通り、newしたタイミングでRenderTextureのメモリが確保されました。

ここまで引っ張っておいてあれですが、これは間違いです。

XcodeとUnityにおける値の乖離

f:id:esakun:20181227121039p:plain:w450
Xcodeのメモリ使用率を見てみると、90MBと値が1.5GBと比べて大きく乖離していることがわかりました。


Unity上 Xcode上
1.5GB 90MB

これはUnityのMemoryProfilerが認識している確保と実際の確保タイミングが違うのではないかということが推測されます。
ということで、第2の予測RenderTextureにピクセルを書き込んだタイミングを確認してみます。


RenderTextureに書き込んだ瞬間、iPhone6sはフリーズし、真っ暗なが画面になり、再起動をし始めました。  Xcode上に以下のダイイングメッセージのような結果を残して。
f:id:esakun:20181227121352p:plain
※OSをクラッシュさせているので、あまりやらない方が良いでしょう

iPhone6sのメモリは最大2GBなので、1.5GBも使ってしまうとそりゃ死にます(もっと早くに気づけたはずorz)。

ということで、メモリの確保のタイミングというのは、


「ピクセルを書き込んだ時」


ということが分かりました。
続いてメモリ解放タイミングについて調べていきます。

メモリ解放タイミングの確認

メモリが解放される予測タイミングは2通りです。

  • RenderTextureをDestroyしてGCが走った時
  • RenderTextureをReleaseした時

確保時同様まずはUnityEditor上で、MemoryProfilerで確認していきます。

結論から言うと、UnityEditor上ではReleaseタイミングでは何も起きず、Destroyした直後にメモリから開放されました。

UnityEditor上での挙動はあてにならないので、確保時同様、実機で確認してみます。

f:id:esakun:20181227124229p:plain

結論から言うと、「RenderTextureをDestroyした時」「RenderTextureをReleaseした時」どちらも同様にメモリが開放されます。GCが走ることなく、Destroyを呼んだ直後に開放されます。

まとめ

RenderTextureの確保はピクセルを書き込んだ時、開放するタイミングはRelease時 or Destroy時ということです。
改めて実機上での挙動を確認する重要性に気付かされました。少々面倒くさくても実機でプロファイリングする癖を付けるのは開発する上では超重要だということですな。

今回のサンプルコートはコチラ

f:id:esakun:20181227125632p:plain:h300
画面上のボタンをポチポチ押しながら確認します。


少しためになったら、はてブください。記事を書く勇気が出てきます^^


以上

参考