したがって、メインスレッドが通常の更新/レンダリングロジックを実行するゲームと、非常に集中的な処理を行う2番目のスレッドがあります。私が抱えている問題は、時々メインスレッドが中断され、ゲームが 60FPS を下回ることです。他のスレッドによってブロックされていることは確かですが、明示的なロックがないため、それを証明する方法がありません。
メイン スレッドがセカンダリ スレッドによってブロックされる理由について、考えられるいくつかのシナリオがあります。
- 2 番目のスレッドは、多数の小さなオブジェクトを割り当てます。メモリ割り当てにより、一方のスレッドが強制的に待機し、もう一方のスレッドがメモリを割り当てます。1 つの小さなオブジェクトを割り当てた後、メイン スレッドが必要なものの割り当てを続行できると予想されるため、これはありそうもないことです。
- 時間がかかりすぎる場合にセカンダリ スレッドが中断されるのを防ぐ、何らかの形式の JIT 最適化。これはまったく意味がありません。
- ロックされているある種のクロススレッド参照。二次スレッドがキューからアイテムを取得するキューによってコードが意図的に分離されている可能性は低いですが、アイテムがキューに配置されるのをロックして防止することはありません。
- この問題は Linux と Windows の両方で発生するため、OS による不適切なスレッドの優先順位付けも非常にまれです。
ストップウォッチを入れて、コードのどの領域に時間がかかるかを測定しようとしましたが、これは「メインスレッドがランダムに 500 ミリ秒停止した」以上のことはほとんどわかりません。メインスレッドを長時間ブロックしているロックがあるかどうかは実際にはわかりません。
この問題の原因を絞り込むために使用できる手法はありますか?
- - - 編集 - - -
これらは、Mono プロファイラーを実行し、ロックの競合について報告した結果です。
Monitor lock summary
Lock object 0x7f05190c9fe0: 1 contentions
0.002126 secs total wait time, 0.002126 max, 0.002126 average
1 contentions from:
(wrapper runtime-invoke) object:runtime_invoke_void__this__ (object,intptr,intptr,intptr)
System.Threading.Thread:StartInternal ()
System.Threading.Timer/Scheduler:SchedulerThread ()
(wrapper unknown) System.Threading.Monitor:FastMonitorEnterV4 (object,bool&)
System.Threading.Monitor:Enter (object,bool&)
System.Threading.Monitor:TryEnter (object,int,bool&)
(wrapper managed-to-native) System.Threading.Monitor:try_enter_with_atomic_var (object,int,bool&)
Lock object 0x7f051910b100: 1 contentions
0.000628 secs total wait time, 0.000628 max, 0.000628 average
1 contentions from:
Ninject.Components.ComponentContainer:Get (System.Type)
Ninject.Components.ComponentContainer:ResolveInstance (System.Type,System.Type)
Ninject.Components.ComponentContainer:CreateNewInstance (System.Type,System.Type)
System.Reflection.ConstructorInfo:Invoke (object[])
System.Reflection.MonoCMethod:Invoke (System.Reflection.BindingFlags,System.Reflection.Binder,object[],System.Globalization.CultureInfo)
System.Reflection.MonoCMethod:DoInvoke (object,System.Reflection.BindingFlags,System.Reflection.Binder,object[],System.Globalization.CultureInfo)
System.Reflection.MonoCMethod:InternalInvoke (object,object[])
(wrapper managed-to-native) System.Reflection.MonoCMethod:InternalInvoke (System.Reflection.MonoCMethod,object,object[],System.Exception&)
(wrapper runtime-invoke) <Module>:runtime_invoke_void__this___object (object,intptr,intptr,intptr)
Ninject.Activation.Caching.ActivationCache:.ctor (Ninject.Activation.Caching.ICachePruner)
Ninject.Activation.Caching.GarbageCollectionCachePruner:Start (Ninject.Activation.Caching.IPruneable)
(wrapper remoting-invoke-with-check) System.Threading.Timer:.ctor (System.Threading.TimerCallback,object,int,int)
System.Threading.Timer:.ctor (System.Threading.TimerCallback,object,int,int)
System.Threading.Timer:Init (System.Threading.TimerCallback,object,long,long)
System.Threading.Timer:Change (long,long,bool)
System.Threading.Timer/Scheduler:Change (System.Threading.Timer,long)
(wrapper unknown) System.Threading.Monitor:FastMonitorEnterV4 (object,bool&)
System.Threading.Monitor:Enter (object,bool&)
System.Threading.Monitor:TryEnter (object,int,bool&)
(wrapper managed-to-native) System.Threading.Monitor:try_enter_with_atomic_var (object,int,bool&)
Lock object 0x7f05190ca000: 1 contentions
0.000347 secs total wait time, 0.000347 max, 0.000347 average
1 contentions from:
(wrapper runtime-invoke) object:runtime_invoke_void__this__ (object,intptr,intptr,intptr)
System.Threading.Thread:StartInternal ()
System.Threading.Timer/Scheduler:SchedulerThread ()
(wrapper remoting-invoke-with-check) System.Threading.EventWaitHandle:Reset ()
System.Threading.EventWaitHandle:Reset ()
(wrapper unknown) System.Threading.Monitor:FastMonitorEnterV4 (object,bool&)
System.Threading.Monitor:Enter (object,bool&)
System.Threading.Monitor:TryEnter (object,int,bool&)
(wrapper managed-to-native) System.Threading.Monitor:try_enter_with_atomic_var (object,int,bool&)
Lock contentions: 3
Lock acquired: 3
Lock failures: 0
これは、ゲームを約 20 ~ 30 秒間実行した結果であり、この間に少なくとも 10 回のラグ スパイクが観察されました。その間、ロックの競合は 3 つしかなく、すべての解決に 16 ミリ秒もかかりません。