GeometryCollectionPhysicsProxy::FieldParameterUpdateCallback() not removing invalid Commands, leading to performance issues.
The licensee has provided their analysis:
We seem to have stumbled across an issue in FGeometryCollectionPhysicsProxy::FieldParameterUpdateCallback(), where the FieldData.Commands buffer is not being cleared, leading to severe performance issues over time. This seems to happen when we apply a LinearForce command to a geometry collection. This causes the IsParameterFieldValid(FieldCommand) check to fail since Field_LinearForce is not listed as a valid PhysicsType for EFieldType::EField_FVector. Due to this failure, the command is not removed from the buffer and the buffer will accumulate commands indefinitely.
This was easy to test with an empty level where a blueprint containing a RadialForce Component was placed next to a geometry collection.
We are using Unreal 5.4 at the moment, but it appears that the issue will still be present in 5.6.
Either adding Field_LinearForce to the list of allowed PhysicsTypes in IsParameterFieldValid() (FieldSystemProxyHelper.h) or moving the CommandsToRemove.Add() logic outside of the the IsParameterFieldValid() check will resolve the issue, but we are not sure which is the correct approach.
I was able to reproduce the behavior on UE 5.4, 5.5, 5.6, and 5.7 (CL44372627) (although, as mentioned in Steps To Reproduce, Commands is extracted into FieldData.Commands at UE 5.5 and up).
In UE 5.4:
Create a blank C++ project
Open the SLN file and Start Debugging (F5) the project from Visual Studio (VS) so we have the Debugger attached to the project process
On the UE Editor
On the default scene
Add a Cube to the scene
Convert it to Geometry Collection (SHIFT+6 -> Fracture Mode -> New -> Save (e.g. GC_Cube) -> Fracture it using Uniform and default settings -> Save
Create a blueprint (e.g. BP_RadialForce)
Add a RadialForceComponent
Save
Spawn it so the radius of influence of the RadialForce encapsulates the GC (spawning at the same spot of GC_Cube is enough)
Go to VS
Put a Breakpoint on
void FGeometryCollectionPhysicsProxy::FieldParameterUpdateCallback(Chaos::FPBDRigidsSolver* RigidSolver, const bool bUpdateViews)
Add a Watch to Commands (on 5.5 and up, the watch should go into FieldData.Commands)
Back to UE Editor, either Play-In-Editor or Simulate-In-Editor
We will immediately be brought back to VS and the hit Breakpoint
Now, either keep Continuing execution (by pressing F5 on Visual Studio), or Disable the breakpoint, leaving the execution running for a while, and later re-enable the breakpoint, at which point execution will stop again.
Check that Num of Commands increases indefinitely and accumulates quickly:
...} FFieldSystemCommand
+ [2] {TargetAttribute="LinearForce" RootNode=Ptr=0x00000826f2ca7480
...} FFieldSystemCommand
+ [4] {TargetAttribute="LinearForce" RootNode=Ptr=0x00000826d086f400
...} FFieldSystemCommand
...
+ [945] {TargetAttribute="LinearForce" RootNode=Ptr=0x00000826d1d6a280
...} FFieldSystemCommand
+ [947] {TargetAttribute="LinearForce" RootNode=Ptr=0x00000826ff8b5080
...} FFieldSystemCommand
+ [949] {TargetAttribute="LinearForce" RootNode=Ptr=0x00000826ff8b6740
...} FFieldSystemCommand
+ [Raw View]
TArray<FFieldSystemCommand,TSizedDefaultAllocator<32>>
> UnrealEditor-Chaos.dll!FGeometryCollectionPhysicsProxy::FieldParameterUpdateCallback(Chaos::FPBDRigidsSolver * RigidSolver, const bool bUpdateViews) Line 5558 C++
UnrealEditor-Chaos.dll!Chaos::AdvanceOneTimeStepTask::DoWork() Line 465 C++
UnrealEditor-Chaos.dll!Chaos::FPBDRigidsSolver::AdvanceSolverBy(const Chaos::FSubStepInfo & SubStepInfo) Line 1387 C++
UnrealEditor-Chaos.dll!Chaos::FPhysicsSolverAdvanceTask::AdvanceSolver() Line 175 C++
UnrealEditor-Chaos.dll!Chaos::FPhysicsSolverAdvanceTask::DoTask(ENamedThreads::Type CurrentThread, const TRefCountPtr<FGraphEvent> & MyCompletionGraphEvent) Line 151 C++
UnrealEditor-Chaos.dll!TGraphTask<Chaos::FPhysicsSolverAdvanceTask>::ExecuteTask(TArray<FBaseGraphTask *,TSizedDefaultAllocator<32>> & NewTasks, ENamedThreads::Type CurrentThread, bool bDeleteOnCompletion) Line 1235 C++
[Inline Frame] UnrealEditor-Core.dll!FBaseGraphTask::Execute(TArray<FBaseGraphTask *,TSizedDefaultAllocator<32>> &) Line 840 C++
[Inline Frame] UnrealEditor-Core.dll!FTaskGraphCompatibilityImplementation::QueueTask::__l5::<lambda>() Line 1970 C++
UnrealEditor-Core.dll!LowLevelTasks::FTask::Init::__l13::<lambda>(const bool bNotCanceled) Line 499 C++
[Inline Frame] UnrealEditor-Core.dll!Invoke(LowLevelTasks::FTask::Init::__l13::void <lambda>(void) &) Line 47 C++
[Inline Frame] UnrealEditor-Core.dll!LowLevelTasks::TTaskDelegate<LowLevelTasks::FTask * __cdecl(bool),48>::TTaskDelegateImpl<`LowLevelTasks::FTask::Init<`FTaskGraphCompatibilityImplementation::QueueTask'::`5'::void <lambda>(void)>'::`13'::void <lambda>(void),0>::Call(void *) Line 162 C++
UnrealEditor-Core.dll!LowLevelTasks::TTaskDelegate<LowLevelTasks::FTask * __cdecl(bool),48>::TTaskDelegateImpl<`LowLevelTasks::FTask::Init<`FTaskGraphCompatibilityImplementation::QueueTask'::`5'::void <lambda>(void)>'::`13'::void <lambda>(void),0>::CallAndMove(LowLevelTasks::TTaskDelegate<LowLevelTasks::FTask * __cdecl(bool),48> & Destination, void * InlineData, unsigned int DestInlineSize, bool <Params_0>) Line 171 C++
[Inline Frame] UnrealEditor-Core.dll!LowLevelTasks::TTaskDelegate<LowLevelTasks::FTask * __cdecl(bool),48>::CallAndMove(LowLevelTasks::TTaskDelegate<LowLevelTasks::FTask * __cdecl(bool),48> &) Line 308 C++
UnrealEditor-Core.dll!LowLevelTasks::FTask::ExecuteTask() Line 627 C++
UnrealEditor-Core.dll!LowLevelTasks::FScheduler::ExecuteTask(LowLevelTasks::FTask * InTask) Line 155 C++
[Inline Frame] UnrealEditor-Core.dll!LowLevelTasks::FScheduler::TryExecuteTaskFrom(LowLevelTasks::Private::FWaitEvent *) Line 362 C++
UnrealEditor-Core.dll!LowLevelTasks::FScheduler::WorkerMain(LowLevelTasks::Private::FWaitEvent * WorkerEvent, LowLevelTasks::Private::TLocalQueueRegistry<1024>::TLocalQueue * WorkerLocalQueue, unsigned int WaitCycles, bool bPermitBackgroundWork) Line 397 C++
[Inline Frame] UnrealEditor-Core.dll!LowLevelTasks::FScheduler::CreateWorker::__l2::<lambda>() Line 70 C++
[Inline Frame] UnrealEditor-Core.dll!Invoke(LowLevelTasks::FScheduler::CreateWorker::__l2::void <lambda>(void) &) Line 47 C++
UnrealEditor-Core.dll!UE::Core::Private::Function::TFunctionRefCaller<`LowLevelTasks::FScheduler::CreateWorker'::`2'::void <lambda>(void),void __cdecl(void)>::Call(void * Obj) Line 406 C++
[Inline Frame] UnrealEditor-Core.dll!UE::Core::Private::Function::TFunctionRefBase<UE::Core::Private::Function::TFunctionStorage<1>,void __cdecl(void)>::operator()() Line 555 C++
UnrealEditor-Core.dll!FThreadImpl::Run() Line 69 C++
UnrealEditor-Core.dll!FRunnableThreadWin::Run() Line 149 C++
UnrealEditor-Core.dll!FRunnableThreadWin::GuardedRun() Line 71 C++
[External Code]
There's no existing public thread on this issue, so head over to Questions & Answers just mention UE-316307 in the post.
0 |
Component | UE - Simulation - Physics - Destruction |
---|---|
Affects Versions | 5.4, 5.5, 5.6, 5.7 |
Created | Aug 30, 2025 |
---|---|
Updated | Sep 11, 2025 |