This room is a mess. I’m constantly getting after my kids to clean their rooms. Why? Because two days later they complain they can’t find one of their favorite toys! It’s not my job to track their toys. But it is my job to track my game’s memory. We can’t leave stuff lying around in memory, or it’s just going to fill up and crash.
Memory management is of supreme importance in mobile game development. And of high importance in any other platform as well. Your game must run forever! You can’t just leave the textures from three levels ago in memory. You have to make sure things get unloaded from memory. But at the same time you don’t want to accidentally unload something you’re still using.
Obviously you will be tracking and deleting your loaded levels and GameObjects. But also remember that the asset bundles themselves have some memory overhead. In fact, on some platforms, you can only have a maximum number of bundles open at a time. You have to clear them out or the app simply crashes!
It’s been a year in the making of this single blog entry. Originally I wanted to discuss the unloading of asset bundles, and I will get to that. But in the course of working on my latest project (warcommander.com) I realized just how deep the rabbit hole goes.
It turns out that knowing when and how to unload a bundle is more art than science. It’s very specific to how you plan on using your assets. Even different assets within the same game have different needs. Here I’m going to describe what Unity allows, but there will need to be a bonus post on how to recognize what assets belong in what category.
The first rule to remember is that a bundle won’t unload anything that’s been loaded until the bundle is closed. I can’t stress this enough! It is not handled the same way the assets built into the player are. Assets loaded via Resources.Load() will go away when they aren’t referenced anymore and you do a Resources.UnloadUnusedAssets(). Bundles don’t do this! They will not unload until the bundle is closed, even if the assets aren’t used anymore. This makes closing bundles absolutely critical to managing memory effectively.
Toward this end, Unity offers two modes of closing a bundle: a) where the contained assets are left in memory and b) where the contained assets are removed from memory. This sounds so simple, but it actually creates significant potential complication.
A naive approach would always use the unloading version, so that you keep open a bundle as long as you’re using any of the assets inside it. However, there are limits to the number of bundles you can have open on some platforms. So what do we do? We unload as early as we can. But even that has a catch – an asset that was left in memory won’t be re-used if the same bundle is reopened later. It will instead make a duplicate copy. So be sure you’re really done with it before closing it!
So where do we go from here? For now, I leave it as an exercise to the reader to work out what bundles you need to keep around and which ones are safe to unload early. Remember to consider how assets shared between two bundles are also distinctly affected by whether the requesting bundles can be unloaded or not.