Potential Memory Leak: colliderToDamageable dictionary in CombatManager retains references to destroyed objects

Subject: Potential Memory Leak / Performance Issue in CombatManager: Dictionary colliderToDamageable not cleaned up on object destruction

Game Version: 1.0.6b

Description:
In CombatManager , there is a dictionary colliderToDamageable that caches IDamageable components for quick lookup during combat queries (e.g., GetCombatTargetsInRadius ). The dictionary is populated in GetCombatTargetsInRadius and similar methods:

csharp

if (!colliderToDamageable.TryGetValue(collider, out var value)) { value = collider.gameObject.GetComponent(); colliderToDamageable.Add(collider, value); }

However, when an IDamageable object (e.g., a raider, building, etc.) is destroyed, the corresponding entry in colliderToDamageable is never removed . The ReportDamageableRemoved method (called when a DamageableComponent is destroyed) removes the object from other lists like allDamageables , raiderFocusedDamageables , etc., but does not touch colliderToDamageable .

This leads to:

  • Dangling references to already-destroyed UnityEngine.Object instances, which may cause MissingReferenceException if accessed later.
  • Dictionary bloat over time, increasing memory usage and lookup overhead, especially in long play sessions with many combat units.
  • Potential performance degradation as the dictionary grows indefinitely.

Steps to Reproduce:

  1. Start a game with combat enabled.
  2. Let multiple raiders/villagers fight and die (or buildings get destroyed).
  3. Over time, the dictionary colliderToDamageable will accumulate entries for every destroyed collider/object that was ever queried.
  4. (Optional) Use a memory profiler to observe the dictionary size and retained entries.

Expected Behavior:
The dictionary should be cleaned up when an object is destroyed, or at least when its IDamageable is removed. A proper implementation could:

  • In ReportDamageableRemoved , also iterate through colliderToDamageable to remove any entries referencing that IDamageable (or its collider). However, since the mapping is from Collider to IDamageable , you’d need to know the collider(s) associated with the object.
  • Alternatively, use a WeakReference or an event system where IDamageable notifies the manager upon destruction, allowing removal from the dictionary.
  • Consider not caching at all, or using a more robust caching strategy that is aware of object lifecycle (e.g., based on instance IDs and cleaned on scene changes).

Suggested Fix:
Add cleanup logic in ReportDamageableRemoved or subscribe to object destruction events to remove entries from colliderToDamageable . For example:

csharp

public void ReportDamageableRemoved(DamageableComponent damageable) { // … existing code … // Remove all colliders associated with this damageable from the dictionary var colliders = damageable.GetComponentsInChildren(true); foreach (var col in colliders) { colliderToDamageable.Remove(col); } }

Additional Context:
This issue was spotted during code review of the CombatManager class. It appears in the game’s source (as decompiled) and may affect long-term gameplay stability and performance. It is not a crash-level bug but could contribute to gradual slowdown.

Thank you for looking into this! Keep up the great work on Farthest Frontier.

2 Likes

Hey! Great find. :muscle: :heart: Thank you. A change is forthcoming.

1 Like