Version: Unity 7.0 Alpha (7000.0)
Language : English
Code reload and assembly load context leaks
Assembly load context leak report reference

Introduction to assembly load context leaks

As you develop and iterate in the Unity Editor, Unity automatically loads and reloads your project code as necessary to incorporate changes you make. This process is referred to as code reload. Code reload involves the following key phases:

  1. Recompiling script assemblies.
  2. Serializing managed objects to save their state.
  3. Unloading or destroying existing script assemblies.
  4. Reloading script assemblies.
  5. Deserializing managed objects to restore their state, and performing any necessary initialization.

By default Unity automatically reloads code as part of an Asset Database refresh, when it detects changes to your scripts or other assets.

If you choose to, you can also configure the Editor to reload code on transition between Edit mode and Play mode.

Code reload and assembly load contexts

The Editor loads assemblies into several instances of AssemblyLoadContext (Microsoft). An AssemblyLoadContext is a .NET mechanism that groups a set of assemblies so that they load and unload together. The Editor puts code with different lifetimes into separate contexts:

  • The .NET base class library and core scripting assemblies load into a context that stays loaded for the whole Editor session.
  • Unity’s Editor and engine assemblies load into long-lived contexts that usually stay loaded across code reloads.
  • Your scripts and package code load into a context that the Editor reloads whenever that code changes.

Because each context loads and unloads as a unit, a code reload unloads only the contexts that need to change, which is usually just the one that holds your code. The long-lived contexts keep their code and data in memory, so the Editor doesn’t need to load them again, and reloads finish faster.

Code reload leaks

Unloading a context is cooperative rather than forced. The Editor asks the runtime to unload the context, and the garbage collector releases it only when nothing outside the context still uses it. A context can unload only when both of the following conditions are true:

  • No thread is running a method from an assembly in the context.
  • No code outside the context references an assembly, a type, or an object from the context. Common examples of such references are a static field or a strong GCHandle.

If either condition isn’t met, the old context stays in memory next to the new one that replaces it. This is a code reload leak.

Code in the long-lived contexts stays loaded across reloads, so any reference that it holds to your code also survives the reload. Most leaks come from a reference of this kind, or from background work that’s still running when the reload starts. For more information about the .NET unloading requirements, refer to How to use and debug assembly unloadability in .NET (Microsoft).

A code reload leak affects your project in the following ways:

  • The memory that the Editor uses grows with every reload, because each leaked context keeps a full copy of your compiled code and its data.
  • The garbage collector needs to scan more objects, which slows down overall performance.
  • Code in a leaked context continues to run, so an event handler that’s still subscribed or a thread that’s still executing can make the same work happen twice.

Identifying leaks

The Editor reports a code reload leak a few seconds after a reload finishes, rather than during the reload itself.

The Console window displays a warning about leaked objects from unloading UnityAssemblyLoadContext instances.

The warning has the following form:

Found 1 leaked object(s) from unloading UnityAssemblyLoadContext instance(s)!
Full leak detection report saved to: C:/MyProject/Logs/ALCLeaks.json
Note: use '-record-managed-allocation-callstacks 1' cmdline argument switch to track callstacks for the leaked GCHandles and '-record-managed-allocation-callstacks 2' for GCHandles and objects.
Leaked types:
1 instance(s) of MyGame.AssetIndex
Root kinds:
1 root(s) of kind Handle with None flags

The types under Leaked types are the objects that the Editor can’t release. The entries under Root kinds describe what holds them.

The following are also symptoms of code reload leaks:

  • The memory that the Editor uses grows after each script change and doesn’t return to its previous level.
  • A callback, event handler, or background task runs more times than you expect, and the number of extra runs grows with each script change.

For more information on interpreting the leak report Unity generates, refer to Assembly load context leak report reference.

Additional resources

Code reload and assembly load context leaks
Assembly load context leak report reference