Description

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).

 

Steps to Reproduce

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:

  • Commands Num=950, Max=1139 TArray<FFieldSystemCommand,TSizedDefaultAllocator<32>>
    + [0] {TargetAttribute="LinearForce" RootNode=Ptr=0x00000826d086f8c0
    Unknown macro: {Magnitude=10.0000000 Position={X=-380.00000000000000 Y=20.000000000000000 Z=49.500100000000003} } ...} FFieldSystemCommand
    + [1] {TargetAttribute="LinearForce" RootNode=Ptr=0x00000826f2ca9600 {Magnitude=10.0000000 Position={X=-380.00000000000000 Y=20.000000000000000 Z=49.500100000000003} }

    ...} FFieldSystemCommand
    + [2] {TargetAttribute="LinearForce" RootNode=Ptr=0x00000826f2ca7480

    Unknown macro: {Magnitude=10.0000000 Position={X=-380.00000000000000 Y=20.000000000000000 Z=49.500100000000003} } ...} FFieldSystemCommand
    + [3] {TargetAttribute="LinearForce" RootNode=Ptr=0x00000826d086fcc0 {Magnitude=10.0000000 Position={X=-380.00000000000000 Y=20.000000000000000 Z=49.500100000000003} }

    ...} FFieldSystemCommand
    + [4] {TargetAttribute="LinearForce" RootNode=Ptr=0x00000826d086f400

    Unknown macro: {Magnitude=10.0000000 Position={X=-380.00000000000000 Y=20.000000000000000 Z=49.500100000000003} } ...} FFieldSystemCommand
    + [5] {TargetAttribute="LinearForce" RootNode=Ptr=0x00000826d086ee80 {Magnitude=10.0000000 Position={X=-380.00000000000000 Y=20.000000000000000 Z=49.500100000000003} }

    ...} FFieldSystemCommand
    ...
    + [945] {TargetAttribute="LinearForce" RootNode=Ptr=0x00000826d1d6a280

    Unknown macro: {Magnitude=10.0000000 Position={X=-380.00000000000000 Y=20.000000000000000 Z=49.500100000000003} } ...} FFieldSystemCommand
    + [946] {TargetAttribute="LinearForce" RootNode=Ptr=0x00000826f2cab900 {Magnitude=10.0000000 Position={X=-380.00000000000000 Y=20.000000000000000 Z=49.500100000000003} }

    ...} FFieldSystemCommand
    + [947] {TargetAttribute="LinearForce" RootNode=Ptr=0x00000826ff8b5080

    Unknown macro: {Magnitude=10.0000000 Position={X=-380.00000000000000 Y=20.000000000000000 Z=49.500100000000003} } ...} FFieldSystemCommand
    + [948] {TargetAttribute="LinearForce" RootNode=Ptr=0x00000826ff8b55c0 {Magnitude=10.0000000 Position={X=-380.00000000000000 Y=20.000000000000000 Z=49.500100000000003} }

    ...} FFieldSystemCommand
    + [949] {TargetAttribute="LinearForce" RootNode=Ptr=0x00000826ff8b6740

    Unknown macro: {Magnitude=10.0000000 Position={X=-380.00000000000000 Y=20.000000000000000 Z=49.500100000000003} }

    ...} FFieldSystemCommand
    + [Raw View]

    Unknown macro: {AllocatorInstance={...} ArrayNum=950 ArrayMax=1139 }

    TArray<FFieldSystemCommand,TSizedDefaultAllocator<32>>

Callstack

> 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]

Have Comments or More Details?

There's no existing public thread on this issue, so head over to Questions & Answers just mention UE-316307 in the post.

0
Login to Vote

Unresolved
ComponentUE - Simulation - Physics - Destruction
Affects Versions5.45.55.65.7
CreatedAug 30, 2025
UpdatedSep 11, 2025
View Jira Issue