
Unity ECS vs GameObjects – A Real Performance Comparison
June 5, 2026
Unity Addressables Guide: Faster Loading and Better Asset Management
June 19, 2026Memory management is one of those topics that many Unity developers ignore at first… until their game suddenly starts stuttering for no obvious reason. Everything looks fine in the editor, the FPS seems stable, and then out of nowhere the game freezes for a fraction of a second.
If that sounds familiar, chances are you are experiencing Garbage Collection spikes.
Unity uses C# and the .NET runtime, which means memory allocation and cleanup are partially handled automatically by a system called the Garbage Collector (GC). While this sounds convenient, it can also introduce performance problems if not managed carefully.
In this guide, we’ll explain how Garbage Collection works in Unity, why it can cause frame drops, and most importantly how you can reduce or avoid GC allocations in your projects.
What is Garbage Collection?
Garbage Collection is an automatic memory management system used by C#. Instead of manually freeing memory like in languages such as C or C++, the runtime periodically looks for objects that are no longer being used and removes them from memory.
For example, when you create a new object in C#:
Enemy enemy = new Enemy();
Memory is allocated on the managed heap. When that object is no longer referenced anywhere in your code, it becomes eligible for garbage collection.
At some point, the Garbage Collector runs and frees that memory.
Sounds great, right? The problem is that the GC process takes time. And when it runs, it can pause the game momentarily while cleaning memory.
In real-time applications like games, even a small pause can cause noticeable frame drops or stutters.
Why Garbage Collection Causes Performance Issues
Unity games run in a real-time loop. Every frame must complete within a strict time budget. For example:
- 60 FPS → ~16.6 milliseconds per frame
- 30 FPS → ~33 milliseconds per frame
If the Garbage Collector suddenly needs several milliseconds to clean memory, your frame might exceed its time budget. When that happens, players experience a visible hitch or freeze.
These are commonly called GC spikes.
The more temporary objects you allocate during gameplay, the more often the Garbage Collector will need to run.
How to Detect Garbage Collection in Unity
Before optimizing anything, you should first check if Garbage Collection is actually happening in your game.
Unity provides several tools for this:
- Unity Profiler
- Memory Profiler
- Deep Profiling
In the Unity Profiler, look at the CPU timeline. If you see entries labeled GC.Collect, that means the Garbage Collector was triggered during gameplay.
You may also notice spikes in frame time whenever this happens.
Common Causes of Garbage Collection in Unity
Many GC allocations come from small coding habits that seem harmless but happen every frame.
Some of the most common causes include:
- Frequent string concatenation
- Creating new objects every frame
- Using LINQ in gameplay code
- Boxing and unboxing values
- Allocating arrays repeatedly
Let’s look at a few examples.
Avoid Allocating Objects in Update()
The Update() function runs every frame. If you allocate memory here, it will accumulate quickly and trigger Garbage Collection.
Example of problematic code:
void Update()
{
Vector3 position = new Vector3(
Random.Range(-5,5),
0,
Random.Range(-5,5)
);
}
Although this example looks harmless, repeated allocations across many scripts can add up quickly.
A better approach is to reuse variables whenever possible.
Be Careful with String Operations
Strings in C# are immutable. That means every time you modify a string, a new object is created in memory.
Example:
void Update()
{
string message = "Score: " + score;
scoreText.text = message;
}
This creates a new string every frame.
A more efficient approach is to update UI text only when the value changes.
public void UpdateScore(int score)
{
scoreText.text = "Score: " + score;
}
This simple change can eliminate thousands of unnecessary allocations during gameplay.
Avoid Using LINQ in Performance-Critical Code
LINQ is convenient and expressive, but it often creates hidden allocations. Using it inside gameplay loops can produce unexpected garbage.
Example:
var activeEnemies = enemies.Where(e => e.isActive).ToList();
This creates temporary objects and lists in memory.
A manual loop is often more efficient in performance-critical sections.
List<Enemy> activeEnemies = new List<Enemy>();
for(int i = 0; i < enemies.Count; i++)
{
if(enemies[i].isActive)
{
activeEnemies.Add(enemies[i]);
}
}
Use Object Pooling
One of the best ways to reduce Garbage Collection in Unity is using Object Pooling.
Instead of creating and destroying objects repeatedly, you reuse existing ones.
This is especially useful for:
- Bullets
- Enemies
- Particles
- UI elements
Simple example of a pooling system:
using UnityEngine;
using System.Collections.Generic;
public class BulletPool : MonoBehaviour
{
public GameObject bulletPrefab;
public int poolSize = 20;
private List<GameObject> pool;
void Start()
{
pool = new List<GameObject>();
for(int i = 0; i < poolSize; i++)
{
GameObject bullet = Instantiate(bulletPrefab);
bullet.SetActive(false);
pool.Add(bullet);
}
}
public GameObject GetBullet()
{
for(int i = 0; i < pool.Count; i++)
{
if(!pool[i].activeInHierarchy)
{
return pool[i];
}
}
return null;
}
}
With pooling, objects are created once and reused many times, which significantly reduces memory allocations.
Reuse Collections Instead of Creating New Ones
Another common source of GC allocations is repeatedly creating new lists or arrays.
Example of inefficient code:
void Update()
{
List<int> numbers = new List<int>();
}
Instead, create the collection once and reuse it.
List<int> numbers = new List<int>();
void Update()
{
numbers.Clear();
}
This avoids unnecessary allocations and reduces pressure on the Garbage Collector.
Understand Boxing and Unboxing
Boxing happens when a value type (like int or float) is converted into an object. This creates an allocation on the heap.
Example:
object value = 5;
While occasional boxing may not matter, frequent boxing inside loops can contribute to garbage collection.
Using strongly typed collections and avoiding unnecessary object conversions can help prevent this.
When Garbage Collection is Actually Fine
It’s important not to become obsessed with eliminating every allocation.
Garbage Collection is not inherently bad. In fact, it simplifies development significantly. The goal is simply to avoid large or frequent allocations during critical gameplay moments.
Allocations during loading screens, menus, or initialization are usually perfectly acceptable.
Optimization should always be guided by profiling rather than guesswork.
Final Thoughts
Garbage Collection is a normal part of C# and Unity development, but understanding how it works can help you avoid many performance issues.
The key strategies are straightforward:
- Avoid allocating objects in Update loops
- Reduce unnecessary string operations
- Avoid LINQ in gameplay code
- Reuse collections and variables
- Use object pooling for frequently spawned objects
Most importantly, always rely on the Unity Profiler to identify real problems before optimizing your code.
With careful memory management, you can eliminate many GC spikes and create smoother gameplay experiences across all devices.










