ハードやPC構成によっては違いは無いと思われますが、GCが何をきっかけに動いているかを調べて頂くとより詳しい条件が分かってくるかと思われます(意図的に手動で実施しているものか、メモリ不足により自動で発生したものか、サブレベルの状態更新によって発生するのか、何らかの設定値をトリガーにGCが行われているか等です)
インクリメンタルGCの時間制限が処理が規定時間 (デフォルト:5ms, gc.IncrementalReachabilityTimeLimit/GIncrementalReachabilityTimeLimit)を超えた場合bIsSuspended=trueになります。これを0.00005に設定なされている場合は極端に短い時間制限で、フレームレートの安定性は向上しますが、GC完了までの時間が大幅に延長され全体的なパフォーマンスが低下する可能性があります。ワーカースレッドが既に動作している状態なのでバックグラウンドでGCの処理は行われている状態ですが、例えばワーカースレッドが非効率に動いているような状態となっていますでしょうか?bIsSuspended=true となっている場合次のフレームでも処理が継続される動作となるので、エンジンは次のフレーム以降でGC処理を継続することを期待しており、GC対象をそのフレームで完了することはデフォルト実装では期待されていない動作となります。
承知しました、別途詳細な質問が新たにございましたら新しいケースでご質問を追加して頂けますと幸いです。
ありがとうございます。
試してみます!
お世話になっております。
教えて頂いた対応でだいぶ負荷軽減ができました!ありがとうございます!
追加で相談ですが、現在下記のように設定しております。
AssetClustreringEnabled=True
Disregard GC Objectを設定済み
gc.IncrementalReachabilityTimeLimit=0.001
gc.IncrementalGatherTimeLimit = 0.001
gc.IncrementalGCTimePerFrame = 0.001
でもまだ、GCの開始時が辺りが2~3msと指定の数字以下にはなかなかならない感じです。
収まるようにすべきことは他にありますでしょうか?
さらに、incrementalGCの最後に行われる「IncrementalPurgeGarbage」が長いのでこちらを削減する方法は無いでしょうか?
よろしくお願いいたします。
[Image Removed]
ありがとうございまうす。
やはりオブジェクト数を減らすしかなそうですね。
AssetClustreringEnabled=True
Disregard GC Objectを設定済み
gc.IncrementalReachabilityTimeLimit=0.0005
gc.IncrementalGCTimePerFrame = 0.0005
に設定しても最初のGC時が1~2msになるのを対処するにもオブジェクト数周りを減らす以外に対処方法は無いでしょうか?
あと、最後のフルパージはエンジン仕様で必ず起こるものという認識でよろしいでしょうか?
[Image Removed]
ご確認頂きありがとうございます。
>また、GC.VerifyAssumptions、GC.VerifyObjectFlagsをハイライトイベントで探ってみてもトレースした情報では見つけることができませんでした。
ConditionalCollectGarbage 内から呼び出しが発生しているかと思いますが、いかがでしょうか?以下のスクリーンショットでそのマーカーを示します。
[Image Removed]
添付の動画ではこのイベントのハイライト方法について示しています。ご確認頂けますと幸いです。
具体的なポイントをInsightsベースでご質問なされる場合はプロファイルデータをご共有頂けますと、こちらでも同じものを確認しながら情報を共有することも可能です。
お世話になっております。
GlobalDefinitions.Add(“ENABLE_STATNAMEDEVENTS=1”);
を入れてビルドしてみたのですが表示が確認できませんでした。
Post Tick Component Updateの表示もなくったていたのでフラグの設定はできていると思われます。
現在、なにもGCの設定を入れていないDevelopmentパッケージではGC.VerifyAssumptions、GC.VerifyObjectFlagsが表示されているのは確認できています。
[Image Removed] [Image Removed]
↓GC周り対応なしのDevパッケージ
[Image Removed]
[Image Removed]
ご返答ありがとうございます。
現状取れる最善策は、プロジェクトを周りをプライベートで診ていただいてアセット参照なども診ていただくということですね。
それ以外ですと、細くプロファイリングと最適化と分析して詰めて細く進めていくしかないということですね。
内部で相談して今後について話し合ってみます。
ご対応ありがとうございます。
ちなみに、お聞きしたいのですが
他のゲームですとよく最適化されてるゲームでGCはどのくらい値なのでしょうか?
現状想定しているのは60FPSのゲームで、1FあたりのゲームスレッドのGCの占有時間を500usなのですが、ここ最近のものはどれくらいの値なのか知りたいです。
あまりGC時間について言及された公開された情報が多くありませんが、以下はFF7Rの一例として挙げられます。
https://realsound.jp/tech/2021/06/post\-790537\.html
マップのロード直後やUIで隠された状態などは特にGCタイミングとして意図して実行されるケースもあり、そのようなケースでは数100ms程度のGC時間も許容されることは多くのタイトルで聞きます。弊社でも数100msを超えるようなケースは最適化の対象とすることが多いですが、現実的な落としどころとしてはゲームプレイに支障のない処理時間というのが多くのケースで利用される指標ではいないかと思われます。そのような値は、動作するデバイスやマシンスペックによっても異なるので、一概にこの値というのは本当にタイトル次第なところではあります。そのため、タイトルによってゲームプレイに支障がないという目標値を決めて、それに向けて最適化を取り組むというのが最終的な取り組みになってくるかと思われます。
色々質問攻めですみません。
本当にありがとうございます。
一旦、上記の毎フレームGCをする形の状態で動作確認をしっかりやってみる形の流れになりました。
GCスタート時の3msをロード画面中になどでにさせて、アクションメインのインゲーム中は500us以下になってる最中で対応してしまおうと思います。
フルパージは、進行の節目や何かしらイベント中に叩くようにした強制GCで対処してみます。
ご返答が遅くなってしまい申し訳ございませんでした。
Windowsにおいてどの部分がGCのネックになっている個所かというのがスクリーンショットからは少し分からなかったのですが、もし添付の赤枠に該当する箇所が現在ご指摘されている個所だとしましたら、これはGCとは別の処理によるものだと推測されます。AibouEnemy…という箇所はマーカーから見えましたが、これに関する何らかのロード処理が走っていることが想定されるため、この箇所をより掘り下げて見て頂くことをお勧めいたします。
[Image Removed]
ご返答ありがとうございます。
GCの処理が合わないというものは、その空いてる部分ではなくGCが終わり毎フレーム行うようにではなく
序盤のデータレイヤーを読み込んでしまったあたりのGCだけでその後は起きなかったの状態のことを指します
PS5、XSXだとこちらのように毎フレームGCをするようになったのですが
[Image Removed]
Win64だと下記のイメージのようにGCが起きたらその後のデータレイヤーを大きく読み込んだときや、イベントなどでGCを発生させたときのみGCが発生します。
[Image Removed]
どちらもDefaultEngine.iniで下記のように設定しているます。
gc.MaxObjectsNotConsideredByGC=55526
gc.SizeOfPermanentObjectPool=16798688
gc.AssetClustreringEnabled=True
gc.IncrementalReachabilityTimeLimit = 0.0001 ; sets the soft time limit to 100μ
gc.IncrementalGatherTimeLimit = 0.0001
gc.IncrementalGCTimePerFrame = 0.0001
gc.TimeBetweenPurgingPendingKillObjects = 0.001
Win64パッケージでも可能なら毎フレーム細くGCをさせておきたいと思います。
ご返答ありがとうございます!
Win環境でのGCが起きるタイミングを確認して調査進めます。
ありがとうございます。
ありがとうございます。
こちらで確認中のWin環境はメモリが潤沢なものが多いのでメモリ不足周りからの調査をしてみようと思います。
他のハードはギリギリまでうまく使ってるので一番怪しそうなところから調査してみます。
お世話になっております。
Win環境でGCがなかなか起きない件ですが、こちらで調べてみたところGarbageCollection.cppにある
else if (NumRechabilityIterationsToSkip == 0 || // Delay reachability analysis by NumRechabilityIterationsToSkip (if desired)
!bIsSuspended || // but only but only after the first iteration (which also does MarkObjectsAsUnreachable)
IterationTimeLimit <= 0.0f) // and only when using time limit (we're not using the limit when we're flushing reachability analysis when starting a new one or on exit)
{
上記のif文の、bIsSuspended がTrueになってることで入らないことが多い流れでした。
このフラグを調べたところ
bIsSuspended = false;
for (int32 WorkerIndex = 0; WorkerIndex < NumWorkers && !bIsSuspended; ++WorkerIndex)
{
bIsSuspended = Contexts[WorkerIndex]->bIsSuspended;
}
の処理でワーカースレッドが一つでも動いてる場合はフラグが入るみたいですが、空いてるワーカーがあるならそちらに投げるなどの対処はできないのでしょうか?
よろしくお願いいたします。
ご返答ありがとうございます。
非効率かもしれないので、ワーカーの動きを精査してみます
現在調査してますが、なかなか確定的な情報が得られないので長引きそうでしたらクローズドで細く相談したいと思います。