質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.31%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Q&A

解決済

1回答

1564閲覧

UniTaskでawait時にGC Allocが発生し,フレームレートが低下する.

leaf21341

総合スコア10

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

0グッド

0クリップ

投稿2023/10/22 18:41

生じている問題

Cysharp.Threading.Tasks.LinqのAwait系を使うと致命的なGC Allocが発生し,フレームレートが低下してしまいます.
UniTaskはzero allocationで有名ですが,UniTaskAsyncEnumerableはその限りではないのでしょうか?
(ちなみに,私はUniRxをあえて採用せずUniTaskAsyncEnumerableを使っています.)

ご回答よろしくお願いいたします.

該当のコード

下記コードでHp(IAsyncReactiveProperty<int>型)が変化した瞬間GC Allocが発生し,大きなフレームレート低下を引き起こします.
Subscribeの中身やawaitする非同期関数の種類は関係なく,SelectAwaitでawaitするとこの現象が引き起こされるようです.

C#

1_playerStatus.Hp.WithoutCurrent() 2 .SelectAwait(async _ => 3 { 4 await UniTask.Delay(2000); 5 return AsyncUnit.Default; 6 }) 7 .Subscribe(_ => 8 { 9 Debug.Log("change HP"); 10 });

ちなみに下記のユースケースでは上記のような現象は発生しません.

C#

1async void Update() 2 { 3 if (Input.GetKeyDown(KeyCode.Space)) 4 { 5 await UniTask.Delay(1000); 6 } 7 }

プロファイラー

UniTaskLoopRunnerUpdateでGC Allocと大きなスパイクが確認できます.
イメージ説明
イメージ説明

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

https://github.com/Cysharp/UniTask#allocation-on-profiler

AsyncStateMachineの割り当てをデバッグビルドではclass、Releaseビルドでは構造体でやる仕様がありここらへんの差異で起きているのではと思ったのですがどうでしょう?
ここら辺を踏まえてもなお改善しない場合はここじゃなくてissueが妥当かもしれません。

またその際にはIL2CPP/Monoバックエンドで挙動が違ったりするのでバックエンドやPlatform、UnityVersion含めて全部記録して実機ビルドでのReportもしたうえで発生条件を整理するとよいと思います。

投稿2023/10/23 02:44

UnitySoldier

総合スコア207

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

leaf21341

2023/10/29 03:28 編集

回答ありがとうございます. >AsyncStateMachineの割り当てをデバッグビルドではclass、Releaseビルドでは構造体でやる仕様がありここらへんの差異で起きているのではと思ったのですがどうでしょう? リリースビルドにしてもGC Allocが発生していたので四苦八苦していたのですが,色々調査した結果async/await自体のGC AllocとUniTask自体のGC Allocを混同していました. つまり,Await系はそもそもasync/awaitのオーバーヘッドが大きくなりがちということですね. (結局,Await系をプレイ中のフレームレートにダイレクトに影響する場面で使わないこととしました.)
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.31%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問