When I run with the commented code and comment out the red code, it doesn’t freeze
You are removing elements from the map while iterating through it, which is not allowed
if you want to do that, you can do that with an iterator instead of a for:
for (auto It = ActiveEffectHandles.CreateIterator(); It; ++It)
{
if (TargetASC == It.Value())
{
TargetASC->RemoveActiveGameplayEffect(It.Key(), 1);
It.RemoveCurrent();
}
}
To diagnose why the FindAndRemoveChecked
method is causing lag, let’s analyze the code and consider potential performance bottlenecks:
for (auto HandlePair : ActiveEffectHandles) {
if (TargetASC == HandlePair.Value) {
TargetASC->RemoveActiveGameplayEffect(HandlePair.Key, 1);
ActiveEffectHandles.FindAndRemoveChecked(HandlePair.Key);
}
}
Potential Issues
-
Loop Overhead:
- If
ActiveEffectHandles
is a large collection, iterating over it can be time-consuming. Each iteration involves checkingTargetASC == HandlePair.Value
and callingRemoveActiveGameplayEffect
.
- If
-
Frequent Removal Operations:
- The
FindAndRemoveChecked
method is likely performing a search to findHandlePair.Key
before removing it. IfActiveEffectHandles
is implemented as a list or array, this operation could beO(n)
in complexity, making the overall loop potentiallyO(n^2)
for large datasets.
- The
-
RemoveActiveGameplayEffect Overhead:
- The call to
RemoveActiveGameplayEffect
could be complex, involving significant processing, especially if it involves additional searches, updates, or events.
- The call to
Performance Improvement Suggestions
-
Use Efficient Data Structures:
- Ensure that
ActiveEffectHandles
uses a data structure with efficient removal operations, such as a hash map or unordered set, which can provide averageO(1)
removal time.
- Ensure that
-
Batch Removal:
- Instead of removing elements inside the loop, collect the keys to be removed and perform batch removal after the loop. This can minimize the performance impact of frequent removals:
TArray<FActiveGameplayEffectHandle> HandlesToRemove; for (auto HandlePair : ActiveEffectHandles) { if (TargetASC == HandlePair.Value) { TargetASC->RemoveActiveGameplayEffect(HandlePair.Key, 1); HandlesToRemove.Add(HandlePair.Key); } } for (auto& Handle : HandlesToRemove) { ActiveEffectHandles.FindAndRemoveChecked(Handle); }
-
Profile and Optimize:
- Use profiling tools to measure the exact time spent in each part of the code. Identify the most time-consuming operations and focus optimization efforts there.
-
Optimize Conditional Checks:
- If possible, optimize the condition
TargetASC == HandlePair.Value
to reduce the time spent on comparisons.
- If possible, optimize the condition
-
Reduce Complexity in RemoveActiveGameplayEffect:
- Investigate the
RemoveActiveGameplayEffect
method to ensure it is optimized and not doing unnecessary work.
- Investigate the
Example of a Potential Optimization
Here’s how you might refactor the code to minimize the performance impact:
TArray<FActiveGameplayEffectHandle> HandlesToRemove;
HandlesToRemove.Reserve(ActiveEffectHandles.Num()); // Preallocate memory to avoid reallocation
for (auto HandlePair : ActiveEffectHandles) {
if (TargetASC == HandlePair.Value) {
TargetASC->RemoveActiveGameplayEffect(HandlePair.Key, 1);
HandlesToRemove.Add(HandlePair.Key);
}
}
for (auto& Handle : HandlesToRemove) {
ActiveEffectHandles.FindAndRemoveChecked(Handle);
}
In this refactored version:
- We collect all handles to remove in a separate array.
- After the loop, we remove all collected handles in one go, reducing the overhead of frequent removals.
By applying these strategies, you should be able to mitigate the lag caused by the FindAndRemoveChecked
method.
Thanks for your reply,It’s very useful.
Thanks for your anwsers,I solved this problem.
This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.