Quick answer: Sprites created with sprite_add are not reference-counted or auto-freed. Every sprite_add needs a matching sprite_delete — track the IDs and free them.

A game loads player avatars from disk with sprite_add. After a few menu visits, memory keeps climbing — old sprites were never deleted.

Dynamic Sprites Are Manual

Built-in (IDE) sprites live for the whole game. Sprites created at runtime with sprite_add, sprite_create_from_surface, etc. are dynamic resources — GameMaker won’t free them for you.

Track and Delete

// when loading
avatar_sprite = sprite_add(path, 1, false, false, 0, 0);

// when replacing or leaving
if (sprite_exists(avatar_sprite)) {
    sprite_delete(avatar_sprite);
}
avatar_sprite = sprite_add(new_path, ...);

Before overwriting the variable, delete the old sprite. Before destroying the instance, delete in Clean Up / Destroy.

Watch Reloads and Re-Entry

The classic leak: a menu room that calls sprite_add in its Create event. Re-enter the room 20 times, leak 20 sprites. Free in the room’s Clean Up event.

Profile It

Use the debug overlay’s memory view (or debug_event) — a steadily climbing texture/sprite memory number with no plateau is the signature of a sprite_add leak.

Verifying

Enter and leave the avatar menu repeatedly. Memory rises while loaded, returns to baseline on exit. No unbounded climb.

“sprite_add allocates; only sprite_delete frees. Pair them like new/delete.”

Same rule for surfaces, buffers, ds_* structures, and audio buffers — anything created at runtime is yours to free.