Skip to content

Instantly share code, notes, and snippets.

@Anmol-1903
Last active April 8, 2026 05:11
Show Gist options
  • Select an option

  • Save Anmol-1903/b637c4c778ee3bcc7d80164541ca616e to your computer and use it in GitHub Desktop.

Select an option

Save Anmol-1903/b637c4c778ee3bcc7d80164541ca616e to your computer and use it in GitHub Desktop.

Unity Memory Optimization: The Buffer Pattern

This Gist demonstrates the difference between High-Allocation and Zero-Allocation patterns in Unity.

The Problem: Garbage Collection (GC) Stutter

When you use the new keyword inside Update(), LateUpdate(), or FixedUpdate(), you are allocating memory on the Managed Heap. When the heap is full, Unity must pause execution to collect the "garbage," leading to micro-stutters and frame drops.

The Solution: Pre-allocation & Buffers

By declaring your collections (Lists, Arrays, Dictionaries) as class members and using .Clear() instead of new, you maintain a flat memory footprint.

How to use this:

  1. Attach the script to any GameObject.
  2. Open the Unity Profiler (Ctrl+7).
  3. Look at the CPU Usage module.
  4. Compare the GC Alloc column between the RunBadWay and RunGoodWay methods.

Shared as part of a technical deep-dive on LinkedIn.

using UnityEngine;
using System.Collections.Generic;
/// <summary>
/// Your Unity game doesn't need a faster GPU. It needs a quieter Garbage Collector. 🧹
/// </summary>
public class MemoryAllocationComparison : MonoBehaviour
{
[Header("The Buffer Pattern βœ…")]
// Pre-allocated buffers
private List<int> _nearbyEnemiesBuffer;
private int[] _enemyDistancesBuffer;
private int _activeArrayElements; // Tracks how much of the array buffer we are using
private void Awake()
{
// THE "GOOD" WAY: Pre-allocate your Lists and Arrays in Awake().
// We set a reasonable maximum capacity so it never needs to resize.
_nearbyEnemiesBuffer = new List<int>(50);
_enemyDistancesBuffer = new int[50];
}
private void Update()
{
// THE GOLDEN RULE: If it’s in Update(), it shouldn't be "new".
if (Input.GetKeyDown(KeyCode.B))
{
FindEnemiesTheBadWay();
}
if (Input.GetKeyDown(KeyCode.G))
{
FindEnemiesTheGoodWay();
}
}
/// <summary>
/// THE "BAD" WAY: SPAWNING TRASH ❌
/// Allocates on the Managed Heap. When full, triggers a "Stop-the-World" collection.
/// </summary>
private void FindEnemiesTheBadWay()
{
// ❌ The Problem: Using 'new List<T>()' inside a frequent loop/method.
List<int> nearbyEnemies = new List<int>();
// ❌ The Problem: Using 'new int[]' inside a frequent loop/method.
int[] enemyDistances = new int[10];
// Simulate finding 10 enemies
for (int i = 0; i < 10; i++)
{
nearbyEnemies.Add(i);
enemyDistances[i] = i * 2; // dummy distance calculation
}
Debug.Log($"[BAD] Processed {nearbyEnemies.Count} enemies. Memory allocated on the heap! πŸ“‰");
}
/// <summary>
/// THE "GOOD" WAY: THE BUFFER PATTERN βœ…
/// 0B of GC Allocation. Memory stays a flat line. No spikes, no stutters.
/// </summary>
private void FindEnemiesTheGoodWay()
{
// βœ… The Solution: Use .Clear() on your pre-allocated list to empty it out.
_nearbyEnemiesBuffer.Clear();
// βœ… The Solution for Arrays: Reset your tracking index instead of creating a new array.
_activeArrayElements = 0;
// Simulate finding 10 enemies
for (int i = 0; i < 10; i++)
{
_nearbyEnemiesBuffer.Add(i);
// Overwrite existing array slots instead of allocating new ones
_enemyDistancesBuffer[_activeArrayElements] = i * 2;
_activeArrayElements++;
}
Debug.Log($"[GOOD] Processed {_nearbyEnemiesBuffer.Count} enemies. 0B GC Alloc! πŸ“ˆ");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment