As an oversimplified example, in using an immutable screen buffer, a change between frames results in allocation of a full buffer rather than overwriting memory within the buffer (though one could probably think of ways to optimize this for the use case). Excess comes either in the form of unnecessary (relative to mutable) memory usage and/or CPU cycles necessary to support high-levels of garbage collection.
> in using an immutable screen buffer, a change between frames results in allocation of a full buffer rather than overwriting memory within the buffer
That’s actually not how clojure’s immutable data structures work. They use structural sharing, so only the portion that changes (roughly) needs new memory allocated, and only the parts that changed get garbage collected, so it is a bit more efficient than that.
But if your frame buffer is text, you can store the text in a rope data structure like JS vms do
So you don't necessarily have an allocation for every single character, but you're still able to share memory between buffers
I've implemented a game engine with immutability (makes for fast cloning in AI search) where much of the game state is shared between clones. With reference counting it also means if there's a unique reference being modified then no copy is made. This same trick is used by Python to optimize string concatenation