# Unity: FMOD Reference Updater takes 15minutes to scan

**URL:** <https://qa.fmod.com/t/unity-fmod-reference-updater-takes-15minutes-to-scan/22119>\
**Category:** Unity\
**Tags:** mac, unity\
**Created:** [September 23, 2024, 4:48pm UTC](https://qa.fmod.com/t/unity-fmod-reference-updater-takes-15minutes-to-scan/22119 "2024-09-23T16:48:50Z")\
**Posts on this page:** 1\
**Showing post:** 28

<div class="post-metadata">

**Author:** ![Ultroman](https://avatars.discourse-cdn.com/v4/letter/u/258eb7/32.png) [@Ultroman](https://qa.fmod.com/u/Ultroman)\
**Post date:** [May 28, 2026, 9:36pm UTC](https://qa.fmod.com/t/unity-fmod-reference-updater-takes-15minutes-to-scan/22119/28 "2026-05-28T21:36:36Z")

</div>

Our project hung during Event Reference Updater, too. I found out why and **fixed it**. Here’s the what and how, with a **full step-by-step guide at the bottom** on how to fix it.

NOTE: I didn’t upload the fully fixed file, as I didn’t want to break any rules or laws, and also this way the fixes are likely to work for many different versions, since they are relatively simple.

## **Issue 1: Editor hangs indefinitely on certain prefabs**

**GetGenericUpdateTasks()** recurses into sub-object fields without any depth limit. On prefabs with components that hold large or self-referential object graphs (e.g. object pools, manager classes with many collection fields), the recursive walk never finishes within a single EditorApplication.update tick, freezing the editor.

### **FIX**

Add a depth guard at the top of **GetGenericUpdateTasks()**. Even going as deep as 8 still makes it ultra-fast. You can change this at your leisure. Whatever you set it to, it no longer continues branching forever.

## **Issue 2: Massive duplicate results and O(n²) cycle detection**

An IEnumerable is used to track visited objects, calling **parents.Contains(value)** for cycle detection, which is incredibly slow! This also only detected direct ancestors in a linear chain, while diamond-shaped references (object A referenced by both B and C) were walked twice. On large graphs this degraded to **O(n²)**.

### **FIX**

Replace the **IEnumerable parents** parameter with a **HashSet** for O(1) lookups, created once per top-level call and shared across all recursive calls.

## **Issue 3: Unmodified prefab instances found in scenes or nested under other prefabs, were reported as duplicate results**

**GetEmitterUpdateTasks()** already correctly skips unoverridden prefab instances by checking **PrefabUtility.GetPropertyModifications()**, but **SearchGameObject()** calls **GetUpdateTasks()**, which routes non-emitter components to **GetGenericUpdateTasks()** which doesn’t check for that. This means every instance of a prefab placed in a scene or under another prefab is fully scanned, even if it has zero overrides, producing duplicate results for every field already reported on the source prefab asset.

### **FIX**

In **SearchGameObject()**, skip any component that is part of a prefab instance with no property modifications on that component.

# **Applying the fixes:**

### Fixing issue 1

We have to add a **depth** parameter to the **GetGenericUpdateTasks()** method, and all the recursive calls within it.

Add the **depth** parameter at the end of the signature, like this…:

```csharp
private static IEnumerable<Task> GetGenericUpdateTasks(object target, string subObjectPath = null, IEnumerable<object> parents = null, int depth = 0)

```

…then add this as the first lines of the method…

```csharp
            if (depth > 8)
                yield break;

```

…then find the recursive calls to it, and add the **depth incrementation**. There are two foreach loops that call it, at the very bottom of the **GetGenericUpdateTasks()** method. Respectively, those lines become:

```csharp
foreach (Task t in GetGenericUpdateTasks(item, FieldPath(subObjectPath, subObjectField.Name, index), parents, depth + 1))

```

and

```csharp
foreach (Task t in GetGenericUpdateTasks(value, FieldPath(subObjectPath, subObjectField.Name), parents, depth + 1))

```

### Fixing issue 2

We need to swap out the **IEnumerable parents** parameter for a **HashSet**. I chose to call it **visitedSet** instead, for clarity.

To optimize the set comparisons, we will add an IEqualityComparer.

Add this somewhere within the **EventReferenceUpdater** class…:

```csharp
        internal sealed class ReferenceEqualityComparer : System.Collections.Generic.IEqualityComparer<object>
        {
            public static readonly ReferenceEqualityComparer Instance = new ReferenceEqualityComparer();
            private ReferenceEqualityComparer() { }
            public new bool Equals(object x, object y) => ReferenceEquals(x, y);
            public int GetHashCode(object obj) => System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(obj);
        }

```

…then go to the signature of **GetGenericUpdateTasks()**, and swap out this…:

```csharp
, IEnumerable<object> parents = null

```

…for this…:

```csharp
, HashSet<object> visitedSet = null

```

…add these lines at the top of the method, right _ **after** _ the **depth** yield we added to fix **Issue 1** …:

```csharp
            if (visitedSet == null)
                visitedSet = new HashSet<object>(ReferenceEqualityComparer.Instance);
            if (!target.GetType().IsValueType && !visitedSet.Add(target))
                yield break;

```

…scroll down a bit, and delete these lines…:

```csharp
                if (parents == null)
                {
                    parents = Enumerable.Empty<object>();
                }

                parents = parents.Append(target);

```

…and lastly replace the remaining references to **parents** with **visitedSet**. There should be two **parents.Contains()** calls and two recursive calls to **GetGenericUpdateTasks()** (the same ones you added **depth + 1** to earlier).

### Fixing issue 3

Find the **SearchGameObject** method, and copy/paste this into the first foreach in it:

```csharp
                // If this component is part of a prefab instance in a scene, skip it unless
                // it actually has overrides. The source prefab asset will be scanned separately.
                if (PrefabUtility.IsPartOfPrefabInstance(behaviour))
                {
                    UnityEngine.Object source = PrefabUtility.GetCorrespondingObjectFromSource(behaviour);
                    PropertyModification[] modifications = PrefabUtility.GetPropertyModifications(behaviour);
                    bool hasOverrides = modifications != null && modifications.Any(m => m.target == source);
                    if (!hasOverrides)
                        continue;
                }

```

TADAAAA! It works, and is super-fast! Spend the saved time enjoying life with your family and being good to yourself.

Best regards, Ultroman the Tacoman

---

_[View the full topic](https://qa.fmod.com/t/unity-fmod-reference-updater-takes-15minutes-to-scan/22119)._
