I love developing for the iPhone. It’s a really fun machine. Small enough to allow very small teams to create great apps, but at the same time powerful enough that you can do some really impressive games. The tools are great, the iteration time is great. It’s was a pleasure all around developing Flower Garden.
Except when it comes to memory, that is.
I really like most of the design calls that Apple made designing the software for the iPhone: Using C and Objective C (instead of Javascript or web-only apps), building it on top of a Unix-like core, and even providing OpenGL (although I would love to have lower-level access to the graphics hardware).
Developing for the iPhone is a mix of PC and game console development. One one side, it’s a fairly open platform with standard APIs (like PCs), and on the other, it has (almost) fixed hardware [1] and a regulated distribution channel (like game consoles). I would even argue that the iPhone borrows the best of both worlds. When it comes to memory, however, the iPhone adopted the worst of both worlds. I feel that Apple completely dropped the ball there. Completely.
On a PC (whether it’s Windows, Mac, Linux, or whatever), you can’t count on having a fixed amount of memory. When your program runs, it can be running in a machine with RAM to spare, or in one with barely enough to run the OS. Or maybe it’s running on a machine with enough RAM but there are fifty other programs running and there’s no memory left for your program.
Fortunately (or unfortunately depending on your point of view), virtual memory allows the operating system to write memory pages back to disk and free up space for your program. Yes, it can cause the program to halt and crawl while memory is being paged out, but it will run. Definitely not an ideal solution for semi-real time applications like games. That’s one of the main causes for choppy, underperforming PC games, but it has worked for many years and will do in a pinch.
On consoles on the other hand, you have a fixed amount of RAM from the start. You know what that amount is, and you can plan for it. In this latest generation of consoles, you still need to give up part of that precious memory to some other processes for user interface and network updates, but even that amount is known ahead of time. You can plan for it, and make your game fit in the memory that you have left.
The iPhone memory situation is… a mess. It’s like a console in that you have a fixed amount of RAM: 128 MB (although I’m sure Apple doesn’t want developers thinking about it so they can roll out iPhones with more memory without affecting existing programs). Because it has a fixed amount of RAM, the iPhone doesn’t provide virtual memory swapping [2]. So far so good. But here’s the kicker: Unlike a game console, the iPhone makes no guarantees about how much memory your application has available when it runs.
Let me say that again: You’re dealing with a fixed-memory environment and you have no way of knowing how much memory will be available to you. Did that sink in yet?
So how are you supposed to deal with that? Apple wants us to be able to dynamically load and unload anything in our programs in response to low-memory warning events. That might work well if you’re loading web pages and just need to unload some cached ones, but that’s far from ideal for games. What are you going to do? Unload part of the level? Get rid of some sounds? Not every game can do that, and even if you could, it would add a huge amount of complexity to something that should be pretty simple.
You can’t even plan on using a fixed minimum amount of memory. From my experiments on my iPhone 3G, it seems that it’s relatively safe to use between 15 to 18MB. Any more than that, and you start getting low memory warnings, and unless you program does something about it, the OS will promptly terminate you. On an iPod Touch, since it’s not running as many background services, you usually have more memory available. I learned that the hard way, because I developed most of Flower Garden on an iPod Touch, only to find out that it was too slow and running out of memory on the iPhone 3G.
And this is out of a total of 128MB. Where did the rest of the memory go? Come on, even with phone, GPS, and music processes in the background, where did the rest of the memory go? Probably the worse culprits are the mail program and Safari, which are left in memory even after you exit back to the springboard (Bad design decision, no cookie!).
And what exactly does it mean “to do something about it” when you get a low-memory warning? You’re supposed to free up as much memory as you can, but is it enough? Who knows! Maybe you free up one megabyte but the OS still decides that you’re taking too much memory and it will kill you anyway. It seems like the worst memory handling scheme ever designed.
As an extreme situation, I have seen as little as 3.5MB available when starting my own program! What are you supposed to do in that case? Most games will just crash back to the springboard. Want to test this? Launch Safari, load 10-15 heavy web pages, quit, and then launch your favorite game. A crash is almost guaranteed. For my next project, I’ll be tempted to respond to a low-memory warning by killing the Safari and Mail processes. That will free up some memory!
To make matters worse, I had the bright idea of combining OpenGL and UIKit for Flower Garden. Some things worked really well, like being able to quickly create some screens with Interface Builder and take advantage of all of Apple’s UI widgets and fonts. Creating the seeds screen or the settings panel was a breeze with UIKit. However, UIKit uses an undetermined amount of memory behind the scenes, which makes all attempts at staying below a certain memory threshold pure black magic. In particular, drawing images to a context apparently causes mysterious caching of bitmaps taking huge performance hits and memory chunks over which we have no control. And game programmers don’t like to feel they have no control over what’s happening!
Another consequence of such a horrible memory situation is that game developers aren’t able to make full use of the resources available. If we’re aiming for 15MB, but have to drop back to 5-8MB, most developers are not going to try to write a game that uses 30 or 40MB (which might be available). What a shame!
I’ve said before that the iPhone very closely resembles the great Sega Dreamcast (which is my favorite game console of all time). The Dreamcast only had 16MB of main RAM and 8MB of video RAM, but the best games on the iPhone, still pale in comparison to the best Dreamcast games. Why? Mostly because of the memory situation. If we had a guaranteed 16MB of RAM and the possibility of using all the extra free memory, iPhone games would look very, very differently.
My plea to Apple: Please, give us some minimum memory guarantees for OS3.0! That, more than anything else, will make the biggest difference in the look and reliability of future games.
[1] There are slight differences between iPhone 2G, 3G, iPod Touch 1st and 2nd gen (especially the latter, which has a faster CPU and faster file system).
[2] It has virtual memory in the sense that there’s a paging system with virtual addressing (so two memory pages far apart in real memory could be made to seem to be continuous), but there is no automatic paging in and out of memory pages to/from disk.