A memory handling system

by jegeblad

The iPhone doesn't have a lot of memory. As programmers we have grown lazy about memory because we are used to 2 GB of RAM and lots virtual memory. Of course, the iPhone doesn't have that. With Lifecards I am constantly running into memory problems. Not the retain/release sort. Mine are of the type that I run out of memory. Lifecards uses a lot of texture memory. Each card is composed of multiple layers that each consists of a bunch of textures. Each photo included takes up additional texture memory. The toolbar takes up texture memory. Text in speech bubbles uses texture memory etc. etc.

The good thing about a lot of this is that all of these textures can in principle be discarded and rebuild at will. E.g. the toolbar icons can be removed from texture memory if they are not currently visible. The main-menu ditto. etc. By removing those items that are not currently used, we can save some memory, and we will require less memory overall.

That is why I am in the middle of changing the memory system for Lifecards now.

Basically, each element that requires some memory is a subclass of a class I call MemChunk.

Each subclass must implement void free(), void generate(), and int size(). I am using C++ for this system, but I could have used Objective C. Each MemChunk also has a bool ready. If ready is false, then the data represented by MemChunk must be generated first. Otherwise, we can safely use it.

The MemChunk superclass includes a function void ensureReady(). ensureReady() must be called before any of the data in the memory chunk is accesses/used. ensureReady calls generate if ready is false and nothing if ready is true. Before calling generate ensureReady also ensures that the memory subsystem has size() bytes available. If not, the memory subsystem will go through all the memory chunks and remove the least recently used memory chunks in order to free up some memory by calling free on each of those chunks.

Now, this is all quite similar to a conventional virtual memory system where page bits of memory can be paged in and out. The difference here is that the memory I need doesn't exist in flat form on the disk. Instead the generate function will generate it on-the-fly based on much smaller data either from the disk, or in rare occasions a much smaller piece of data in memory. Examples of generation can be as simple as loading a png-file, creating a texture containing text, or a full set of complex drawing instructions. In principle it can be anything. If the data must be freed from memory it is simply deallocated -- I don't write it down in flat format as you would in a virtual memory system.

In reality 90 % of all of the memory Lifecards uses lies in this category. Even photos stay on disk unless they are used to generate textures or the finished graphics.

There is a couple of neat features. Firstly, I can control much better how much memory I use. I can set the maximum memory I want to use for this subsystem to e.g. 10 MB and if I use more than that chunks will get freed. I can also use the system to keep control over which components I am currently using. If I get a memory warning from the system I can just drop everything which should help a bit in the short-term. Finally, if I forgot to free memory of a chunk manually, it will most certainly happen automatically when I need it.

The reason I started developing the system was the amount of memory used by the toolbar icons in the last submitted version 1.2.2. Each toolbar icon is 64x64x32 bit so with 64 toolbar icons that is a whole 1 MB I use just for the toolbar icons. I use an additional 128 KB for the shiny glass effect of the toolbar. I would like to add more icons and other things that are going to require more memory. In short, I had to do something. The text of the speech bubbles actually already used a similar system to ensure that the app doesn't crash when you generate 20 bubbles and therefore would run out of texture memory.

I love keeping things simple and it would have been great not to implement this, but it is really a nice little simple system with the core running in a little less than 150 lines of code. I can certainly see myself using it for lots of other things.